Skip to content

V1 Compiler Implementation Tasks

Working direction

Implementation task plan extracted from Scope Backlog. The scope backlog owns language-design acceptance; this page owns later compiler sequencing, modularity, and verification work.

This page tracks implementation and verification work needed after the V1 language design is accepted. It should not introduce new language semantics. If a task discovers a missing or contradictory language rule, update the owning design page and the Scope Backlog before treating the implementation behavior as settled.

V1 scope is complete. The slices below are implementation sequencing only; they do not defer accepted V1 language features.

Architecture Rules

Catalyst implementation should stay modular, with small phase-local modules and typed artifact boundaries inspired by Compiler Pipeline and Phase Boundaries.

  • Every phase has a typed input artifact and typed output artifact.
  • Later phases consume only the previous phase's public artifact.
  • Debug consumers and stubs are allowed in early slices, but they must use the same artifact boundary as the real implementation.
  • Backends consume VerifiedIR rather than unverified IR.
  • The interpreter consumes VerifiedIR rather than unverified IR, including in comptime mode.
  • Parser code must not resolve names, infer types, or query the type table.
  • Sema must not emit C-specific forms or backend layout structs.
  • Lowering must not recover source syntax from tokens or AST trivia.
  • C backend output must not rerun semantic checks, inspect AST attributes, or call sema helpers.
  • Snapshot output is part of the public implementation contract for each phase that exists in a slice.
  • Stubs must be explicitly named in the slice that allows them and removed or tracked before V1 final acceptance.

Implementation Toolchain

The reference compiler implementation targets Zig 0.16.0.

Agent implementation tasks should assume Zig 0.16.0 for build files, standard-library APIs, test commands, CI setup, and generated examples. Do not silently update the compiler implementation to another Zig version during a slice. If a task needs a different Zig version because of a toolchain bug, missing API, or release availability issue, report the blocker in the handoff and ask for explicit approval before changing the target version.

Module Boundaries

The implementation should use concrete subsystem boundaries. Exact source paths may vary, but ownership should stay clear.

Module Ownership
driver CLI parsing, command dispatch, input/output path handling, session construction, exit codes
session immutable invocation config, phase options, shared services, selected target, safety mode, build profile
target normalized target facts: pointer width, endianness, maximum object alignment, bit-precise integer support, selected C ABI family, target-selected layout facts
source file loading, file IDs, source text, spans, path normalization primitives
modules root module registry, module identity, namespace loading, include/module resolution policy, module manifests, import/re-export filtering, dependency diagnostics
diagnostics structured diagnostics, notes, warnings, fatal errors, deterministic rendering
hooks typed HookBus, deterministic hook ordering, phase-owned hook points
lex source text to tokens and trivia
parse tokens to AST and syntax diagnostics, using Catalyst Source Grammar as the source grammar map
ast AST node storage, spans, deterministic AST dumps
names scopes, namespaces, imports, visibility, symbol IDs
types type table, primitive types, type constructors, layout queries
sema AST to SIR, type checking, name resolution, source semantics
sir semantic artifact model and deterministic dumps
comptime demand interface, compiler-owned handles, intrinsic registry metadata, host-intrinsic dispatch, interpreter bridge
lower SIR to IR lowering, lowering-intrinsic expansion
ir IR data model, verifier, deterministic IR dumps
interp verified IR interpreter
backend_c C emission from verified IR only
prelude seeded prelude loading and bootstrap support
lint lint passes over hook points and artifacts
tests snapshot harness and integration runner

HookBus

Hooks are internal compiler extension points, not a public V1 plugin API.

Hook points are typed and phase-owned. A hook point declares:

  • input artifact;
  • allowed outputs or mutations;
  • deterministic ordering;
  • diagnostic authority;
  • whether it may affect source semantics;
  • whether it may abort the current phase or compilation.

Hooks may observe, transform, emit diagnostics, and error out only when the hook-point contract grants that authority. Hooks must not reach around the current artifact boundary. Semantic-changing hooks are compiler-owned in V1. Lints should be implemented through hooks or artifact passes when possible; if a lint needs semantic facts owned by a phase, the phase may expose those facts through a typed hook point rather than hardwiring lint policy into unrelated code.

Hook execution order is part of the hook-point contract:

  • hook points run in fixed pipeline order;
  • within a hook point, compiler-owned hooks run by explicit registration group: normalization, lint, then debug/check;
  • within each group, hooks run by stable hook ID, not source discovery order, map iteration order, filesystem order, or module load order;
  • hooks that may mutate an artifact must declare that authority in the hook-point contract and must run before observe-only hooks for the same artifact.

V1 should start with these internal hook points:

Hook point Artifact Default authority
after_parse AST observe; emit syntax/style/lint diagnostics; abort only through fatal diagnostics
after_sema SIR observe; emit semantic/lint diagnostics; abort for hard semantic diagnostics
before_verify IR observe; compiler-owned normalization hooks may transform when explicitly registered; abort for lowering/verifier-prep diagnostics
after_verify VerifiedIR observe; no transform; emit backend-independent warnings/debug checks; abort only for internal consistency failures
before_emit_c VerifiedIR observe; no transform; emit backend diagnostics; abort for unsupported target/backend forms

Slice Format

Each vertical slice should record:

  • goal;
  • accepted source subset;
  • required real modules;
  • required snapshots or runtime outputs;
  • allowed stubs;
  • forbidden shortcuts and anti-leak rules.

Each slice or sub-slice should be directly assignable to an implementation agent by ID. A request such as "implement Slice 0a from compiler/v1-implementation-tasks.md" means the agent must implement that slice's local requirements, inherit the parent slice requirements, follow this page's architecture rules, and consult the linked canonical docs before inventing behavior.

Every agent handoff should return:

  • summary of behavior implemented;
  • commands run;
  • fixtures and snapshots added or updated;
  • stubs introduced or retired;
  • phase-boundary notes for any new artifact or cross-module dependency;
  • design ambiguities or contradictions discovered;
  • recommended next slice or sub-slice.

Early slices may stop at the latest implemented boundary or use a debug consumer. Once a slice claims executable behavior, it should pass through SIR, IR, verifier, and at least the interpreter unless the slice explicitly says otherwise.

Implementation should follow the test strategy in Testing: prefer tracer-bullet TDD, add one failing public behavior fixture at a time, and keep snapshot updates in the narrowest phase that proves the rule.

Comptime Capability Ladder

Comptime is a cross-cutting implementation spine, not a single isolated feature slice. Each slice that consumes comptime must name the comptime capability it relies on and the compiler-owned handles or intrinsics it adds.

The capability ladder is:

  • Slice 17 establishes the demand interface, primitive comptime values, already-known primitive Type handles, function item values, explicit comptime parameters, ordinary function calls during demanded comptime evaluation, and the typed intrinsic registry with category/effect/context metadata.
  • Slice 18 adds prelude bootstrap use: primitive factory wrappers, primitive aliases, source-loaded prelude declarations, Namespace handles as needed for module and include, and validation roots that demand the prelude surface.
  • Slice 20 adds attribute-provider use: provider registration contexts, attribute target handles, target mutation APIs, provider evaluation, and provider diagnostics.
  • Slices 22 and 23 add contract use: contract factory instances, operation guards, contract surface handles, conformance facts, and contract-related cache dependencies.
  • Slice 24 verifies reflection use: public reflection operations over compiler-owned handles, wrong-kind diagnostics, visibility behavior, and cross-feature metadata consistency.

No slice may introduce a second comptime evaluator. If a prelude, attribute, contract, or reflection feature cannot be expressed through the shared comptime demand interface plus explicit compiler intrinsics, the slice must extend those mechanisms rather than adding a side path.

Vertical Slice Plan

Slice 0: Source, Tokens, and AST Skeleton

Goal: load one .ct file, lex it, parse a tiny function/module, and emit token and AST snapshots.

Accepted source: fn main() void { return void }.

Required real modules: driver, session, target, source, diagnostics, hooks, lex, parse, ast, tests.

Required outputs: .tokens.snap, .ast.snap, .diag.snap, and selected .stderr.snap for syntax errors.

Agent context for all Slice 0 sub-slices: consult Compiler Pipeline, Phase Boundaries, Testing, Diagnostics, and Catalyst Source Grammar. Use the grammar page as the parser map only; focused source-form pages own semantic rules when they disagree with the grammar map. Sub-slices inherit the Slice 0 accepted source, required modules, outputs, allowed stubs, and forbidden shortcuts unless a sub-slice narrows them further.

Required driver behavior: parse a minimal CLI with commands such as tokens, ast, and check; accept an input path; select output mode; construct a Session with default target/profile/safety facts; return deterministic exit codes for success and diagnostics.

Required snapshot workflow: test mode must support stable snapshot paths/names, deterministic mismatch diffs, and local snapshot update mode such as --update-snapshots.

Required diagnostic shape: structured diagnostics must exist from Slice 0 with severity, stable diagnostic code/ID, primary span, optional secondary spans, labels, notes, hints, deterministic technical output, and deterministic stderr rendering from that technical output.

Required parser recovery: syntax diagnostics must support deterministic multi-error recovery from Slice 0 onward, using Catalyst Source Grammar as the parser's source-form map. The parser should synchronize at ;, }, EOF, and top-level declaration starters such as fn, const, var, struct, enum, contract, and impl; recovery diagnostics must use SourceStore spans, notes, and hints where useful, and must not infer semantic meaning while resuming.

Required literal syntax coverage: string literal forms including byte escapes, and code point literal forms are tokenized and represented in AST snapshots, but typed string/text literal values are not semantically accepted until the standard text surface owns their representation.

Required expression parser coverage: precedence and associativity snapshots must prove AST grouping for accepted operator tokens and call/member/index forms as they become syntactically available. Slice 0 owns parser grouping; later slices own semantic meaning.

Sub-slices:

  • 0a: driver, session, target, and source-store scaffold. Build the minimal command surface, immutable session config, default target/profile/safety facts, single-root .ct file loading, file IDs, source text storage, and span primitives. Required outputs may be limited to harness smoke output and deterministic command exit behavior. Allowed stubs: commands may stop before lexing/parsing, but command names, input path handling, and session construction should already be real.
  • 0b: diagnostics model and deterministic rendering. Add structured diagnostics with severity, stable code/ID, primary span, optional secondary spans, labels, notes, hints, deterministic technical output, and deterministic non-color stderr rendering from SourceStore spans. Required outputs: .diag.snap and selected .stderr.snap for source-loading or deliberately injected scaffold diagnostics. Allowed stubs: no parser diagnostics yet.
  • 0c: snapshot harness and fixture metadata. Add stable fixture discovery, stable snapshot paths/names, deterministic mismatch diffs, and local update mode such as --update-snapshots. Required outputs: at least one passing fixture and one failing diagnostic fixture. Allowed stubs: phase outputs not implemented yet may be rejected by harness diagnostics rather than silently skipped.
  • 0d: HookBus scaffold. Add typed hook-point registration for Slice 0 artifacts with built-in no-op hooks only, deterministic registration order, and no public plugin API. Required outputs may be limited to unit coverage or a small scaffold snapshot if the implementation exposes hook-order debugging early. Allowed stubs: hooks may not transform artifacts or affect source semantics.
  • 0e: lexer and token snapshots. Tokenize the accepted source subset plus comments/trivia, identifiers, keywords, separators, delimiters, operators needed by the grammar map, and literal token forms including string spelling, byte escape spelling, and code point spelling. Required outputs: .tokens.snap and .diag.snap for lexical errors. Forbidden shortcuts: lexing does not resolve names, assign types, or classify identifiers beyond the reserved-word filter.
  • 0f: AST model and deterministic AST dump. Add AST node storage, source spans, syntax-only names as written, metadata/trivia attachment needed by early snapshots, and a deterministic AST dump format. Required outputs: scaffold .ast.snap fixtures once parser nodes exist. Forbidden shortcuts: AST nodes do not store semantic IDs, resolved symbols, inferred types, or backend facts.
  • 0g: minimal parser for the tiny accepted program. Parse fn main() void { return void }, top-level item lists, function declarations, parameter lists, return type syntax, blocks, return expressions, primitive literal expressions, and the separators needed by that source. Required outputs: .ast.snap, .diag.snap, and selected .stderr.snap. Allowed stubs: unsupported grammar forms may produce deterministic syntax diagnostics.
  • 0h: parser recovery and multi-error syntax diagnostics. Add deterministic recovery at ;, }, EOF, and top-level declaration starters such as fn, const, var, struct, enum, contract, and impl. Required outputs: focused .diag.snap and selected .stderr.snap fixtures proving multiple syntax errors in one file. Forbidden shortcuts: recovery diagnostics use SourceStore spans and do not infer semantic meaning while resuming.
  • 0i: parser coverage hardening for literals and expression grouping. Add AST representation and parser snapshots for string literal syntax including byte escapes, code point literal syntax, precedence and associativity grouping for accepted operator tokens, and call/member/index postfix forms as they become syntactically available. Required outputs: focused .ast.snap fixtures. Boundary: this sub-slice proves parser grouping only; typed literal values, operator meaning, indexing semantics, and call resolution remain later slices.

Allowed stubs: sema, lowering, IR, interpreter, and C backend may be absent; source loading may handle only one root file; HookBus may have only built-in no-op hooks.

Forbidden shortcuts: parser does not type-check; AST does not store semantic IDs; diagnostics use SourceStore spans instead of ad hoc raw byte offsets.

Slice 1: Primitive Sema and SIR Snapshots

Goal: resolve local/top-level names and type-check primitive declarations and expressions into SIR.

Accepted source: top-level constants, local constants, primitive annotations, returns, and primitive arithmetic such as return answer + 1.

Required real modules: names, types, sema, sir, plus previous slice modules.

Required outputs: .sir.snap, .diag.snap, and selected .stderr.snap for name/type errors.

Required semantics: primitive type identities, integer literals as comptime_int, annotation-driven literal coercion where the target type is explicit, primitive arithmetic result typing, block and return typing, local scopes, and top-level const lookup.

Required reference coverage: within-file top-level forward references for accepted primitive const/function cases, plus deterministic cycle diagnostics for invalid recursive const evaluation or declaration dependencies.

Allowed bootstrap: primitive type identities may be seeded directly by types before prelude loading exists. This is not a public alias mechanism. When prelude bootstrap lands, aliases such as i32 and u32 must be loaded from prelude source and resolve to the same canonical Type IDs.

Allowed stubs: no comptime execution except literal evaluation; no modules/imports/include; no structs, methods, pointers, arrays, or slices; no IR/lowering/interpreter/C backend.

Forbidden shortcuts: SIR contains resolved symbol/type IDs, not raw name strings as semantic references; sema does not emit IR-shaped control flow; type table is owned by types, not parser or AST.

Slice 2: Inference and Expected-Type Semantics

Goal: make core inference behavior explicit before lowering/backend slices depend on typed SIR.

Required semantics: local binding type inference, inference-context plumbing for later function result inference, inference-driven contextual literal resolution, numeric coercion and inference diagnostics, range endpoint fallback inference, expected-type shorthand for leading-dot members, inference failure diagnostics, and ambiguity diagnostics.

Boundary: Slice 2 does not complete ordinary function return inference or expression-bodied => function inference. Slice 3 owns inferred function signatures, block/final-expression completion, and arrow-body parsing/checking.

Allowed stubs: no generic inference, contract inference, comptime parameter inference, overload inference, broad reflection, or module/prelude-driven inference.

Forbidden shortcuts: inference is sema-owned and produces typed SIR; lowering never guesses types; expected-type shorthand resolves through sema/type context, not parser name lookup.

Slice 3: Function Surface Completion

Goal: cover accepted V1 function source forms before lowering depends on function assumptions.

Required features: explicit and inferred return types, expression-bodied => functions, final-expression completion, main entry-point rules, parameter binding patterns, default parameter values, trailing argument omission, function item values in comptime positions, runtime function pointers for concrete signatures, function type expressions, and an internal default calling-convention field in function type identity.

Sub-slices:

  • 3a: function body shape, block expressions, return expressions, explicit discard expressions, and return inference. Parse expression-bodied => function bodies, parse real block expressions using the shared block syntax, keep block-bodied functions as the existing syntax shape, move return into expression AST/SIR as a never-typed expression whose payload contributes to function return inference, add explicit discard expressions _ = expr with void completion, add SIR statement completion types, infer omitted return types from statement completion in the accepted primitive subset, model local declaration completion as void, and snapshot explicit/inferred return consistency diagnostics.
  • 3b: main entry-point rules. Validate accepted main signatures against the currently implemented type universe, emit deterministic diagnostics for invalid main return types, and keep driver/runtime behavior deferred until executable slices exist.
  • 3c: default parameters and trailing omission. Preserve default parameter metadata, enforce that only trailing positional parameters may be omitted, type-check default values in declaration scope, and materialize omitted arguments for SIR call checking once calls are semantically supported.
  • 3d: function type identity, function item values, and runtime function pointers. Add function type expressions, compile-time-known function item values, compatible function-item-to-pointer coercions, runtime function pointer types for concrete signatures, and the internal default calling-convention field in function type identity. When direct function calls become semantically checked here, add call fixtures for Slice 3c default-argument behavior: full arguments, trailing omission of defaulted parameters, too few required arguments, and the positional-call rule that only the trailing defaulted suffix may be omitted.
  • 3e: parameter binding patterns. Add parameter binding-pattern syntax and diagnostics, with _ binding support first. Keep struct/array destructuring behind a deferred diagnostic for now, and replace that diagnostic with real binding expansion in the aggregate/array slices once those type facts exist.

Allowed stubs: no closures, anonymous functions, overloads, named arguments, comptime parameter inference, source @callconv parsing/storage, C ABI import/export, or full C ABI validation.

Forbidden shortcuts: parser preserves source shape, sema owns signature inference; function items are not runtime values unless converted to accepted function pointer forms; lowering receives a resolved callable target, not raw call syntax.

Slice 4: Tiny IR and Debug Dump

Goal: lower Slice 3 SIR into a tiny structured IR, verify it, and dump it deterministically.

Accepted source: primitive functions returning primitive values, direct primitive arithmetic, simple locals, and direct internal calls between accepted primitive functions.

Required real modules: lower, ir, verifier, debug IR dump, plus previous slice modules.

Required outputs: .ir.snap, .diag.snap, and selected .stderr.snap for lowering/verifier errors.

Required IR: modules, functions, parameters, locals/constants, direct internal calls between accepted primitive functions, primitive integer checked add for the accepted subset, stable trap kind, and return.

Boundary: Slice 4 lowers sema-successful runtime forms in its accepted subset unless explicitly deferred. Runtime IR lowering requires concrete runtime primitive types; comptime_int values must already be coerced to concrete runtime types before this path. Runtime IR excludes comptime fn units; comptime execution through IR remains owned by Slice 17. Slice 4 does not lower indirect function-pointer calls yet.

IR shape: use IR-local type and value identities, real blocks and terminators even for single-block functions, direct calls by IR FunctionId, typed runtime constants, module-level target and safety-mode facts, and optional source-derived debug names/spans as provenance only. Public .ir.snap output is verified IR only; lowering or verifier failures produce diagnostics instead of dumping malformed IR. Lower demanded top-level constants only when they are present in SIR; lowering must not ask sema or AST to demand more constants.

Allowed stubs: interpreter and C backend absent; verifier may check only IDs, type consistency, terminators, and return type.

Forbidden shortcuts: debug dump consumes IR or verified IR only and is not treated as a backend; IR contains no AST IDs, source names as semantic references, unresolved symbols, or contract facts; optional source-derived debug names are provenance only and are not identity, lookup, verifier, ABI, or linkage facts; lowering does not call C backend helpers.

Slice 5: HookBus and Trivial Lints

Goal: make hooks real by running deterministic built-in hooks over useful AST, SIR, IR, and VerifiedIR artifacts.

Accepted source: Slice 4 source plus simple comments, identifiers, unused declarations, redundant semicolons, and extra whitespace needed by lint fixtures.

Required real modules: hooks, lint, diagnostics, plus previous slice modules.

Required outputs: .diag.snap and selected .stderr.snap for warnings/lints, plus a hook-order snapshot that proves the HookBus ordering policy is stable.

Required diagnostic coverage: first real warning/lint snapshots must exercise the structured diagnostic payload shape, warning versus lint classification, hook diagnostic authority, labels, notes, and hints.

Required hook points: after_parse(AST), after_sema(SIR), before_verify(IR), after_verify(VerifiedIR), and before_emit_c(VerifiedIR) may be stubbed until C emission exists.

Required trivial lints: at least two simple lints over real artifacts, such as naming-convention warnings over AST/SIR, unused local or unused top-level const warnings over SIR, redundant semicolon/trivia warnings over AST/trivia, or debug-only IR shape warnings over IR.

Allowed stubs: hooks may be compiler-owned only; no public plugin API; no semantic-changing hooks except explicitly registered compiler-owned before_verify normalization; no lint configuration, suppression, autofix, or project policy.

Forbidden shortcuts: lints do not run by being hardcoded into parser/sema branches unless the phase exposes a typed hook point; hooks do not access global compiler internals outside the hook contract; lint diagnostics use the shared diagnostics module.

Slice 6: Verified IR Interpreter for Primitive Functions

Goal: execute Slice 4 verified IR and compare deterministic runtime results/traps.

Accepted source: direct primitive functions and one direct internal call.

Required real modules: interp, plus previous slice modules.

Required outputs: runtime-result snapshots, deterministic checked-trap diagnostics/output, and optional test-harness output snapshots for demo programs that need observable runtime text before std.io exists.

Required interpreter behavior: function entry, direct internal call frames, primitive constants, local values, checked integer add, return, and stable trap kinds.

Allowed stubs: no memory model beyond value locals; no comptime mode; no C backend. A compiler-owned test/demo output hook may exist only in the harness and must not be exposed as Catalyst source syntax, prelude API, std.io, or a Compiler.print intrinsic.

Forbidden shortcuts: interpreter consumes verified IR only; interpreter does not evaluate AST/SIR; trap behavior is based on IR checks/traps, not rediscovered source rules; test/demo output does not become a public language-visible I/O surface.

Slice 7: C Backend for Primitive Direct Calls

Goal: emit deterministic C from Slice 6 verified IR for primitive functions and direct calls.

Required real modules: backend_c, plus previous slice modules.

Required outputs: .c.snap.

Required C backend behavior: deterministic function order, primitive integer type mapping for standard widths, direct calls, return values, and checked add lowering for the small accepted subset.

Allowed stubs: no C ABI import/export; no non-standard integer widths unless target reports bit-precise integer support; no structs/pointers/arrays/slices; no debug info or optimization.

Forbidden shortcuts: backend consumes verified IR only; backend does not inspect SIR types, AST names, attributes, or source spans except IR-provided diagnostic span refs.

Slice 7b: C Toolchain Integration Smoke

Goal: compile generated C for the Slice 7 subset into an executable and run small end-to-end source-to-binary smoke tests when a supported local C toolchain is available.

Required behavior: discover or configure a C compiler, invoke it with deterministic output paths, pass target/session facts needed by the backend driver, run the produced executable for primitive direct-call fixtures, compare stdout/exit-code snapshots, and emit deterministic skip diagnostics when no supported C toolchain is available.

Allowed stubs: no full linker model, cross-compilation, package build graph, installed-library discovery, debug info, optimization control, C ABI import/export, or non-default target matrix.

Forbidden shortcuts: toolchain integration consumes generated C and backend/session facts; it does not inspect AST/SIR attributes or rerun semantic checks; smoke tests must be skippable without changing language validity or phase snapshots.

Slice 7c: Target Negotiation Smoke

Goal: prove non-default target facts flow through the existing pipeline before layout-heavy and ABI-heavy slices depend on them.

Required behavior: snapshot default and selected non-default target facts; exercise pointer width, endianness, maximum object alignment, selected C ABI family, and bit-precise integer support; prove session and target facts reach type/layout queries, IR facts, interpreter assumptions where observable, and C backend emission; emit deterministic diagnostics for unsupported target/feature combinations.

Allowed stubs: no full cross-compilation matrix, platform linker discovery, C ABI import/export, target-specific standard library selection, or target-specific optimization policy.

Forbidden shortcuts: target facts come from the target module through session, not ad hoc backend conditionals; C backend and interpreter consume normalized target facts instead of querying host platform behavior directly.

Slice 7d: Runtime Function Pointer Calls

Goal: lower, interpret, and C-emit indirect calls through concrete runtime function pointer values.

Required behavior: function-item-to-pointer values that were type-checked in Slice 3, local storage of concrete function pointers, indirect function-pointer call IR, verifier signature checks, interpreter call frames through function pointer values, and deterministic C emission for function pointer calls.

Allowed stubs: no C ABI callback interop, no dynamic dispatch, no closures, no bound methods, no overloads, and no comptime parameter inference.

Forbidden shortcuts: function pointer calls lower from resolved SIR callable targets into IR indirect-call facts; interpreter and C backend consume verified IR only and do not inspect SIR call expressions.

Slice 8: Structured Control Flow

Goal: compile and run structured blocks, if, while, break, and continue.

Required real modules: sema, lower, ir, verifier, interp, backend_c.

Required IR: branch, conditional branch, return, mutable locals/stores, comparison, checked add/sub/neg.

Allowed stubs: no for, ranges, defer, resource cleanup, arrays, or slices.

Forbidden shortcuts: conditionals and loops lower through IR control flow, not interpreter-side AST execution; C backend emits from IR blocks, not reconstructed source syntax.

Slice 9a: Enums and Case Resolution

Goal: support tag-only enums, enum unions where accepted, and shared case-resolution machinery before error sets depend on similar shorthand behavior.

Required features: enum { ... } type expressions, enum values, enum case identity, duplicate diagnostics, leading-dot shorthand for enum-like cases, enum unions where accepted, and enum reflection basics.

Allowed stubs: no optionals, optional binding, general pattern matching, exhaustive match, payload enums, discriminated unions, error sets, or value reflection.

Forbidden shortcuts: enum and later error expected-type shorthand uses shared owner-resolution machinery; enum reflection is produced from type facts, not parser-only syntax.

Slice 9b: Optionals and Narrowing Basics

Goal: support optional types, optional binding, and basic narrowing before error handling depends on related success/error flow.

Required features: ?T, null, presence coercion, orelse optional defaulting, .? forced optional unwrap with checked traps, if const optional binding, while const optional loops, optional reflection basics, and reusable narrowing machinery.

Allowed stubs: no general pattern matching, exhaustive match, payload enums, discriminated unions, error narrowing, or value reflection.

Forbidden shortcuts: optional binding narrows in sema/SIR, not interpreter source execution; narrowing facts are represented in typed artifacts rather than rediscovered by later phases.

Slice 10: Structs, Fields, Pointers, and Catalyst Layout

Goal: type-check, lower, interpret, and C-emit concrete structs, field access, simple methods, address-of, dereference, and pointer mutability.

Required real modules: types layout support, aggregate sema, field access lowering, IR memory ops, interpreter local/field memory model, C struct emission.

Required outputs: SIR, IR, C, runtime, and deterministic layout snapshots or layout sections.

Required reference coverage: mutually recursive aggregate declarations where accepted, pointer-mediated recursive structs, and deterministic diagnostics for invalid by-value recursive layouts.

Allowed stubs: only .catalyst layout; no arrays/slices; no heap allocation; no resource ownership beyond ordinary locals.

Forbidden shortcuts: layout is computed by types/layout, not by C backend; C backend consumes finalized layout facts from IR; interpreter uses the same layout facts where observable.

Slice 11: Fixed Arrays and Checked Indexing

Goal: support [N]T, array literals, array indexing, mutable element assignment, and checked bounds.

Required modules: array type model, array literal/index sema, array_index_addr, load/store, explicit bounds checks, interpreter array storage, C array emission.

Required checks: index type checking, comptime-known length, and bounds-check trap in Checked mode.

Allowed stubs: no slices, range expressions, for over arrays, array-to-slice coercion, or generic arrays beyond concrete [N]T.

Forbidden shortcuts: bounds checks are explicit IR checks; C backend does not rederive array length from AST; interpreter and C backend consume the same IR indexing facts.

Slice 12: Slices, Ranges, and Slicing

Goal: support slice descriptors, array-to-slice views, range values, slicing, and slice indexing.

Required modules: range typing, range fallback inference, slice descriptors, slicing sema/lowering, slice range checks, interpreter descriptor behavior, C descriptor emission.

Required outputs: SIR, IR, runtime, and C snapshots for indexing, slicing, and range failures.

Allowed stubs: no for; no iterator contracts; no dynamic iteration; no hidden allocation.

Forbidden shortcuts: omitted-bound slicing is sema-owned; range and slice checks are explicit IR checks; backends consume descriptor facts from IR.

Slice 13: Basic Non-Contract for

Goal: support for over ranges, arrays, and slices using staged built-in lowering only.

Required modules: loop-source sema for built-in range/array/slice sources, loop lowering, interpreter/C backend loop execution.

Allowed stubs: no iterator contracts, Iterable, iter, iter_dyn, hidden allocation, or resource-owning iterator cleanup beyond simple loop locals.

Reconciliation rule: by the iterator-contract slice, this staged lowering must either be replaced by the canonical loop-source selection path or become the built-in fast path behind the same canonical source-selection result. No later feature may depend on a second independent for implementation.

Forbidden shortcuts: built-in for lowering is clearly marked as the staged non-contract subset and later reconciled with iterator-loop source selection.

Slice 14: Error Returns, try, and catch

Goal: support closed error sets, T!E, T!, try, catch, and inferred error sets for non-resource values.

Sub-slices:

  • 14a: closed error sets and explicit T!E, with success returns and qualified error returns.
  • 14b: catch fallback forms, including catch fallback, catch { ... }, and catch as err { ... }.
  • 14c: try propagation for compatible errors.
  • 14d: inferred T!, including errors from try, returned errors, fallible tail expressions, and recursive inference diagnostics.

Required modules: error-set types, fallible SIR facts, IR result operations, interpreter result values, C result lowering.

Allowed stubs: no resource cleanup during error propagation; no errors across C ABI; no rich error reflection; no allocation-backed fallible APIs.

Forbidden shortcuts: try/catch lower through explicit result/error IR operations; catch binding uses accepted catch as err { ... } grammar; C backend does not encode errors as ad hoc magic returns outside IR result lowering.

Slice 15: defer Without Resources

Goal: support defer lowering for ordinary calls and early exits.

Required modules: defer sema, cleanup-edge lowering, IR control flow for generated defer calls, interpreter/C execution.

Allowed stubs: no resource ownership, move-state diagnostics, heap allocation, or dynamic dispatch.

Forbidden shortcuts: defer lowering is explicit before backend consumption; C backend does not recover defer semantics from source.

Slice 16: Move State and Cleanup Skeleton

Goal: support move-state analysis, cleanup-state analysis, generated cleanup edges, live overwrite diagnostics, double cleanup diagnostics, and cleanup interactions with return, try, and defer before real resource metadata exists.

Required regression coverage: try, catch, return, and defer must be re-tested with cleanup-state and the synthetic cleanup marker so Slice 14 error lowering cannot silently bypass generated cleanup edges.

Allowed scaffolding: a compiler-owned test-only cleanup marker or synthetic resource kind may be used to exercise cleanup mechanics. This marker cannot leak into language semantics and must be retired or replaced by finalized @resource metadata before V1 final acceptance.

Allowed stubs: no heap allocation, Box, dynamic dispatch disposal, real @resource, or contract-based resource requirements.

Forbidden shortcuts: cleanup is represented in SIR/lowering, not injected by C backend; move-state diagnostics are sema-owned; generated cleanup lowers to ordinary IR calls/branches.

Slice 17: Basic Comptime Substrate

Goal: represent comptime-known values and evaluate simple top-level constants and demanded function calls without modules, prelude bootstrap, attributes, or contracts.

Sub-slices:

  • comptime value representation for primitive values and already-known primitive Type handles;
  • comptime-only function item values;
  • lazy top-level const evaluation in one file with dependency tracking and cycle diagnostics;
  • forced comptime expr and comptime { ... } over already-supported executable expressions;
  • comptime fn and explicit comptime parameters;
  • demanded comptime calls to ordinary fn declarations when the call path and inputs are comptime-available;
  • audit and route Slice 1-16 comptime-adjacent behavior, including comptime_int literal storage/coercion, function item values, default-argument comptime facts, and expected-type shorthand dependencies, through the shared demand interface or explicitly document why a behavior remains sema-only;
  • typed compiler intrinsic registry with stable IDs, comptime_host versus lowering_expansion categories, effect/dependency classes, context requirements, result storage categories, and compiler-owned provenance;
  • simple diagnostic intrinsics such as Compiler.note, Compiler.warn, and Compiler.err;
  • intrinsic registry snapshots covering seeded Compiler declarations, public signatures, categories, effects, context requirements, and provenance summaries.

Allowed stubs: no module/include loading, prelude source bootstrap, attributes, contract factories, reflection enumeration, or incremental cross-run cache.

Forbidden shortcuts: executable comptime code uses SIR -> IR -> verifier -> interpreter; compiler-owned handles are opaque values; host intrinsics use explicit handlers with narrow authority objects; lowering intrinsics expand to ordinary IR; no generic compiler intrinsic call survives into verified backend IR.

Slice 18: Minimal Namespace Loading and Prelude Bootstrap

Goal: build the module-loader core once, then load prelude through that same path with a compiler-provided root namespace.

Sub-slices:

  • module-loader core: namespace identity, loaded source unit identity, declaration table, public/private declaration filtering, deterministic load diagnostics;
  • compiler-provided roots, including prelude and a future std root stub;
  • prelude source load, starting with one file;
  • implicit prelude import into user roots through the same internal import mechanism as later user imports;
  • primitive factories and aliases through prelude source functions over public compiler intrinsics such as primitive type construction and top-error-set construction;
  • Namespace handles as needed for prelude-defined module and include wrappers;
  • prelude validation roots that demand and snapshot-check primitive factories, primitive aliases, Error, module, include, and range helpers as those declarations become active.

Allowed stubs: no full std, no user-facing import syntax, no third-party modules, no contracts/Allocator/Box unless inert declarations are needed.

Forbidden shortcuts: prelude may be compiler-known as a root namespace, but it must not be injected by manually copying declarations into user scopes outside the normal import/resolution machinery.

Slice 19: User Modules, Imports, and Include

Goal: support user-facing module/include mechanics using the same namespace loader/import core as prelude.

Sub-slices:

  • declaration-scope include("./file.ct") with relative path resolution, stable source identity, and deterministic duplicate/cycle diagnostics;
  • module("std") and named root modules, with std allowed to be a tiny stub module first;
  • explicit import forms accepted by V1;
  • minimal module.toml, loose-file synthesized module context, namespace destructuring imports, re-export behavior, import conflicts, root escape checks, manifest dependency diagnostics, cross-file forward references and cycles, and multi-file snapshots.

Allowed stubs: tiny placeholder std; no package manager, manifest evolution, incremental cache, or broad source-text reflection.

Forbidden shortcuts: user module lookup uses the same loader/import core as prelude; include/module do not bypass sema with textual concatenation.

Slice 20: Attribute Syntax, Registration, and Provider Metadata

Goal: parse attributes, register provider functions, resolve provider calls, evaluate simple providers at comptime, validate targets, and write normalized declaration metadata.

Sub-slices:

  • attribute provider registration through Compiler.register_attribute_provider(provider, spec);
  • provider registry entries for identity, target kinds, repetition/conflict policy, ordering, and duplicate/invalid registration diagnostics;
  • attribute syntax and AST/SIR storage;
  • provider lookup and target validation;
  • comptime provider evaluation through ordinary comptime functions, compiler-owned target handles, and explicit target mutation APIs;
  • first concrete metadata providers such as @deprecated, @align, and @repr(.catalyst).

Allowed stubs: no broad attribute target expansion, expression/local attributes, user-generated declarations, arbitrary semantic rewrites, @resource, or C ABI providers unless the relevant later slice is active.

Forbidden shortcuts: attributes do not patch AST directly; providers mutate only through explicit compiler target APIs; IR receives only finalized backend-facing metadata, not raw attributes.

Slice 21: @resource Integration

Goal: replace cleanup scaffolding with real resource metadata from attributes.

Sub-slices:

  • @resource provider target validation and normalized resource metadata;
  • dispose operation shape validation;
  • copyability metadata;
  • resource reflection/provider APIs;
  • cleanup obligations and generated cleanup IR driven by finalized resource metadata.

Required regression coverage: repeat the Slice 16 try, catch, return, and defer cleanup tests after @resource metadata replaces the synthetic cleanup marker.

Allowed stubs: no heap allocation, Box, dynamic dispatch disposal, or contract-based resource requirements.

Forbidden shortcuts: resource metadata comes from finalized attributes, not type-name checks or synthetic test markers; generated cleanup lowers to ordinary IR calls/branches.

Slice 22: Static Semantic Contracts

Goal: support contract definitions, explicit impls, visible conformance lookup, operation checking, and static contract dispatch.

Sub-slices:

  • contract { ... } and generic contract factory functions;
  • demanded comptime contract factory instances with explicit comptime arguments and dependency recording;
  • required operations;
  • impl Type as Contract { ... };
  • operation signature compatibility, inherent-member fill, coherence, and visibility;
  • static operation lookup, qualified contract calls, and direct-call lowering;
  • anonymous static *impl C parameters in function parameter position only.

Allowed stubs: no dyn, default methods, operation guards, contract dependencies/intersections, or ContractSurface.current().

Forbidden shortcuts: conformance is explicit only, never structural; static dispatch resolves in sema; IR contains direct calls, not semantic contract references.

Slice 23: Contract Surface Completion

Goal: complete accepted static contract surface semantics before allocation and dynamic dispatch depend on them.

Required features: default methods, operation guards evaluated as demanded comptime instances, ContractSurface.current().is_static() through compiler-owned contract surface handles, contract dependencies, intersections, constrained local annotation diagnostics, anonymous impl pointer rejection outside function parameter position, conformance reflection, and deterministic diagnostics for guarded/invalid operation surfaces.

Allowed stubs: no borrowed or owned dynamic dispatch yet.

Forbidden shortcuts: operation guards evaluate through comptime machinery; default-method wrappers and dependency facts are represented before lowering.

Slice 24: Reflection Surface Pass

Goal: verify public reflection names, metadata shapes, wrong-kind errors, visibility behavior, and cross-feature consistency after the main producers of reflection facts exist.

Required coverage: public reflection operations over compiler-owned comptime handles, primitive Type classifiers, Type.Predicate fact propagation, optional/enum/function/attribute/layout/source reflection, structural satisfaction reflection, conformance reflection, dyn-safety metadata names where available, public metadata names, visibility behavior, and deterministic wrong-kind diagnostics.

Feature slices still own their local reflection facts. This pass verifies that the public reflection surface is coherent across features.

Allowed stubs: no runtime value reflection, namespace enumeration, Type.Expr, Type.Value, or broad source-text access.

Slice 25: Allocator Contract and Concrete Box(T)

Goal: support the Allocator contract, std.mem.FixedBufferAllocator, concrete allocation/deallocation, placement initialization, and Box(T) ownership for concrete sized T.

Sub-slices:

  • Allocator contract and AllocError;
  • std.mem.FixedBufferAllocator, initially with a compiler-owned smoke-test fixture allowed;
  • placement initialization, typed pointer formation, alignment/layout validation, and failure cleanup;
  • Box(T) create/destroy and move-only ownership.

Allowed scaffolding: the compiler-owned FixedBufferAllocator smoke-test fixture must be retired once std.mem.FixedBufferAllocator is source-backed, or explicitly tracked as remaining scaffolding before V1 final acceptance. It must not become hidden compiler magic for allocation semantics.

Allowed stubs: no *dyn Allocator, Box(dyn C), dynamic dispose descriptors, free-list/reset APIs, or broad allocator catalog.

Forbidden shortcuts: allocation calls go through static Allocator dispatch; Box is prelude/source-level abstraction, not a backend primitive; C backend does not special-case Box semantics.

Slice 26: Borrowed Dynamic Dispatch

Goal: support dyn-safety, borrowed *dyn C / *const dyn C, descriptors, vtables, dynamic calls, and borrowed upcasts.

Sub-slices:

  • dynamic surface computation and dyn-safety;
  • descriptor/vtable constants;
  • forming borrowed dyn pointers from concrete references;
  • dynamic call lowering;
  • dependency upcasts and intersections for borrowed dyn.

Allowed stubs: no owned Box(dyn C), dynamic disposal descriptors, or *dyn Allocator unless needed by a borrowed dyn smoke test.

Forbidden shortcuts: dyn calls use descriptor metadata, not source contract lookup in backend.

Slice 27: Owned Dynamic Dispatch with Box(dyn C)

Goal: support Box(dyn C), box_dyn, into_dyn, private disposal state, dynamic dispose descriptors, and owned upcasts.

Required features: *dyn Allocator where needed, erased allocation authority, dynamic dispose metadata, Box(dyn C) private layout, and cleanup integration.

Allowed stubs: no dynamic iteration yet.

Forbidden shortcuts: owned dyn disposal uses descriptor/dispose metadata, not type-name checks; Box(dyn C) public layout remains private.

Slice 28: Dynamic Iteration and Boxed Iterator Forwarding

Goal: support explicit iter_dyn / iter_dyn_mut, boxed dynamic iterators, and loop use of borrowed/boxed dynamic iterators.

Sub-slices:

  • Iterator, Iterable, and MutableIterable contract families;
  • boxed iterator forwarding for Box(dyn Iterator(Item));
  • explicit iter_dyn(alloc) / iter_dyn_mut(alloc);
  • allocation failure cleanup for dynamic iterator construction;
  • loop over *dyn Iterator(Item) and Box(dyn Iterator(Item));
  • reconciliation of staged built-in for with canonical iterator-loop source selection.

Allowed stubs: no owned iter_dyn_owned, hidden allocation in plain for, or broad std iterator helpers.

Forbidden shortcuts: plain for item in xs does not secretly call iter_dyn; dynamic iteration allocation boundary remains explicit.

Slice 29: Scalar C ABI Interop

Goal: support accepted V1 scalar C ABI import/export/callconv/link-name metadata and deterministic diagnostics for unsupported ABI forms.

Sub-slices:

  • evaluate and validate ABI attributes such as @extern(.c), @export(.c), @callconv(.c), and @link_name after generic attribute parsing/storage has already run;
  • bodyless C-like import rejection;
  • ABI-safe type validation for accepted primitive scalar and pointer forms;
  • function-pointer ABI positions;
  • internal symbol naming;
  • error-return and compound-type rejection diagnostics;
  • SIR/IR ABI metadata for call convention, linkage, external symbol, and import/export facts;
  • C backend extern/export emission and duplicate-link-name diagnostics.

Allowed stubs: no compound C ABI, C struct layout, error-return ABI, varargs, or callbacks beyond accepted function pointer forms.

Forbidden shortcuts: C backend consumes resolved IR ABI facts only; providers validate before backend emission; backend does not inspect raw source attributes.

Slice 30: Diagnostics and Lint Boundary Pass

Goal: audit diagnostic categories, lint boundaries, warning behavior, and hook diagnostic authority before final integration.

Required coverage: cross-feature diagnostic consistency, warning versus lint versus hard-error boundaries, comptime Compiler.note / warn / err, lint catalog smoke tests, explicit deferral of lint configuration/suppression/autofix, hook diagnostic authority audit, and source spans across modules/includes/prelude.

Forbidden shortcuts: lint findings do not define source validity; warnings and hard errors remain phase-owned; comptime diagnostics use the same diagnostics module and deterministic rendering path.

Slice 31: V1 Integration Matrix and Hardening

Goal: prove accepted V1 features compose through the modular pipeline.

Named example targets:

  • primitive_arithmetic_and_range_inference.ct;
  • modules_include_and_prelude.ct;
  • structs_arrays_slices_ranges_for.ct;
  • errors_try_catch_and_cleanup.ct;
  • resource_defer_and_early_exit.ct;
  • static_contract_dispatch.ct;
  • allocator_fixed_buffer_and_box.ct;
  • borrowed_dyn_dispatch.ct;
  • boxed_dyn_dispatch.ct;
  • dynamic_iterator_boxed_forwarding.ct;
  • scalar_c_import_export_smoke.ct.

Required outputs: token/AST snapshots where syntax is relevant, SIR snapshots for semantic-heavy cases, IR snapshots for lowering-heavy cases, structured diagnostic snapshots, selected rendered stderr snapshots, interpreter runtime snapshots, C output snapshots, and selected compile-and-run C smoke tests.

Required architecture checks: backend consumes verified IR only; hooks have deterministic order and explicit authority; no phase reaches around artifact boundaries; earlier stubs are removed or explicitly tracked as post-V1 gaps.

Assigned Coverage Additions

The slice plan above is the primary implementation sequence. The items below assign accepted V1 coverage to concrete slices so implementation work does not rely on implicit ownership. This list is about implementation coverage only; it does not reopen V1 scope.

  • Slice 0 owns comments, documentation comments as trivia, newline-significant statement separation, semicolon handling, parser-contextual continuation diagnostics, expression parser precedence/associativity snapshots, and rejected deferred syntax forms. Slice 24 owns public source metadata reflection that exposes normalized source facts.
  • Slice 1 owns primitive declarations, within-file top-level forward references, deterministic recursive declaration/const cycle diagnostics, shadowing diagnostics, assignment expression typing for primitive values, annotation-driven literal coercion where the target type is explicit, true, false, base-prefixed integers, numeric suffix parsing that is accepted in V1, and rejected literal forms that do not require later feature context.
  • Slice 2 owns inference-driven contextual literal resolution, explicit numeric conversion diagnostics, range endpoint fallback inference, expected-type shorthand for leading-dot members, contextual aggregate-literal typing hooks, and target/safety-mode context in inference snapshots.
  • Slice 3 owns expression-bodied arrow function bodies, ordinary return inference, main entry-point rules, parameter binding patterns, default parameter values, trailing argument omission, function item values, runtime function pointers, function type expressions, and an internal default calling-convention field in function type identity. Slice 29 owns source @callconv parsing, validation, and ABI-facing facts.
  • Slice 5 owns the first naming-convention and documented-convention lints, redundant semicolon/trivia lints, unused declaration lints where enough SIR exists, deterministic hook ordering snapshots, and proof that lints are not hard source validity.
  • Slice 7b owns local C toolchain discovery/configuration, generated-C compilation, executable production, source-to-binary smoke snapshots, and deterministic skip diagnostics when no supported C toolchain is available.
  • Slice 7c owns target negotiation smoke coverage for non-default target facts, unsupported target/feature diagnostics, and proof that normalized target facts flow through session, type/layout queries, IR, interpreter, and C backend emission.
  • Slice 9a owns enum type expressions, enum values, enum unions where accepted, expected-type shorthand for enum/error-like cases, and enum reflection producers.
  • Slice 9b owns optional types, optional binding, while const, rejected while var, orelse, .? forced unwrap/check traps, optional reflection producers, and reusable narrowing machinery.
  • Slice 10 owns aggregate recursion coverage, pointer-mediated recursive structs, invalid by-value recursive layout diagnostics, opaque pointer recovery operations such as cast, as_type, assume_aligned, their diagnostics, and layout/alignment facts for .catalyst structs.
  • Slice 13 owns static built-in iterator sources for ranges, arrays, and slices, for var, loop result type void, deferred value-producing loop diagnostics, and temporary hidden cleanup only for staged loop locals. Slice 28 reconciles this with canonical iterator-loop source selection.
  • Slice 18 owns complete prelude bootstrap for primitive factories, primitive aliases, Namespace, module, include, Error, AllocError, Ordering, range helpers, inert core contract declarations needed before contract sema, Box declarations before allocation is active, Allocator declarations before implementation, and V1 attribute-provider declarations before provider registration is active.
  • Slice 19 owns minimal module.toml, loose-file synthesized module context, re-export behavior, namespace destructuring imports, import conflicts, module/include root escape checks, manifest dependency diagnostics, cross-file forward references and cycles, and multi-file source-span stability.
  • Slice 20 owns Compiler.register_attribute_provider, provider repetition/conflict rules, provenance reflection producers, all accepted declaration attribute targets, @repr(.catalyst), @align, @deprecated, and generic parsing/storage for ABI-named attributes before scalar ABI validation.
  • Slice 21 owns @resource semantics, resource reflection/provider APIs, and transition from the Slice 16 synthetic cleanup marker to finalized resource metadata.
  • Slice 22 owns core prelude contract families needed for static dispatch, including arithmetic contracts, built-in primitive conformances, PartialEq, Eq, PartialOrd, Ord, Indexable, MutableIndexable, Sequence, MutableSequence, Disposable, and array/slice/range conformances that do not require dynamic iteration.
  • Slice 23 owns structural constraints such as satisfies(...) and mutable_fields(...), structural satisfaction reflection producers, opaque static returns, contract dependencies/intersections in static contexts, constrained local annotation diagnostics, and function-type/local/field/type-alias rejection for anonymous impl pointers.
  • Slice 24 owns primitive Type classifier predicates, Type.Predicate fact propagation, source/function/attribute/layout reflection APIs, function type reflection, conformance reflection polish, public reflection metadata names, and wrong-kind/visibility diagnostics.
  • Slice 25 owns the std.mem allocator surface, std.mem.FixedBufferAllocator, allocation visibility diagnostics for concrete Box(T), and failure-cleanup lowering for allocation-backed concrete ownership.
  • Slice 28 owns IndexIterator, MutableIndexIterator, existing-iterator for, hidden iterator cleanup, dynamic iterator construction snapshots, erased allocator authority lifetime lint candidates, allocation failure cleanup, and no hidden allocation in plain for.
  • Slice 29 owns scalar C ABI details: bodyless C-like import rejection, accepted scalar ABI-safe set diagnostics, internal symbol naming, function-pointer ABI positions, duplicate link-name diagnostics, and error-return/compound-type rejection diagnostics.
  • Slice 0 owns compiler diagnostic payload shape, stable diagnostic codes, span labels, notes, hints, and deterministic rendering. Slice 5 owns first warning/lint classification and hook diagnostic authority coverage. Slice 30 owns cross-feature diagnostic consistency, comptime-produced warnings/errors, lint catalog smoke tests, explicit deferral of lint configuration/suppression/autofix, and realtime/allocation-visibility policy warnings that are diagnostics rather than validity rules.
  • Slice 31 owns typed string/text literal value semantics through std.text, final standard-library skeleton namespace smoke coverage for std.Result, std.text, std.mem, std.collections, std.hash, std.fmt, std.debug, std.io, std.math, std.sort, and std.testing, plus final IR/verifier coverage for every accepted backend-visible fact: optionals, enums, attributes, layout/alignment, cleanup, dynamic descriptors, dispose descriptors, calls, traps, ABI facts, and source-span references.

Coverage Checklists

These checklists make sure the vertical slices cover every accepted V1 workstream. They are not the implementation order.

Compiler Skeleton

Source design:

Tasks:

  • Implement the compiler with phase-local data and typed IDs.
  • Keep source loading, diagnostics, hooks, lexing, parsing, sema, lowering, IR, interpreter, and C backend in separate modules with typed artifact boundaries.

Syntax and Source Forms

Source design:

Tasks:

  • Parser snapshots cover newline statement separation, semicolon handling, contextual continuation, and braces in blocks versus aggregate/call contexts.
  • Literal snapshots cover accepted primitive literals, parsed string literals including byte escapes, parsed code point forms, null, undefined, deterministic rejection of deferred literal forms, and deterministic unsupported-use diagnostics for typed string/text literals before std.text owns their representation.
  • Declaration and binding snapshots cover shadowing, assignment typing, destructuring forms, and rejected destructuring-assignment/rest forms.

Functions and Calls

Source design:

Tasks:

  • Parser, sema, reflection, and function-pointer snapshots cover declarations, methods, parameter binding patterns, defaults, inferred returns, and C callconv function types.
  • Function item values are rejected in runtime storage with deterministic diagnostics.
  • Deferred anonymous functions, closures, bound methods, overloads, named arguments, and comptime parameter inference are rejected or parked in V2 diagnostics.

Comptime and Compile-Time Evaluation

Source design:

Tasks:

  • Comptime value snapshots cover primitive values, opaque compiler handles, primitive Type handles, and deterministic comptime_int storage limits.
  • Demanded comptime snapshots cover ordinary fn calls, comptime fn calls, function item values, explicit comptime parameters, dependency recording, and cache-key inputs for semantic instances.
  • Intrinsic registry snapshots cover seeded declarations, public signatures, stable IDs, comptime_host versus lowering_expansion categories, effect/dependency classes, context requirements, result storage category, and compiler-owned provenance.
  • Comptime evaluation uses the SIR to IR to verifier to interpreter path for executable code, with explicit compiler intrinsic handlers for compiler-owned objects.
  • Lowering expansion snapshots prove primitive operation intrinsics such as integer add/compare expand into ordinary IR and do not survive into backend-verified IR.
  • Prelude bootstrap, type factories, contract factories, attribute providers, and reflection operations use the same comptime demand interface instead of a separate interpreter.

Errors

Source design:

Tasks:

  • Error snapshots cover closed error sets, inferred T!, try, all accepted catch forms, error expected-type shorthand, and recursive inference diagnostics.
  • Lowering snapshots show explicit result/error IR operations and cleanup behavior for try, catch, return, and defer.
  • Unsupported error-return ABI and rich deferred error-reflection cases have deterministic rejection tests.

Modules, Namespaces, Imports, and Package Boundaries

Source design:

Tasks:

  • Module-loader snapshots cover root namespace identity, loose-file synthesized module context, module.toml, module(...), include(...), imports, re-exports, destructuring imports, conflicts, root escapes, and cycles.
  • Prelude loading uses the same internal namespace/import path that later user modules use.
  • Multi-file diagnostics retain stable source IDs, spans, and deterministic load order.

Prelude

Source design:

Tasks:

  • Prelude bootstrap snapshots cover primitive aliases/factories, Namespace, module, include, Error, AllocError, Ordering, range helpers, Allocator, Box, core contract declarations, and accepted V1 attribute declarations.
  • Prelude validation roots demand and snapshot-check the public declarations needed by later language features instead of relying on namespace visibility alone.
  • Prelude declarations resolve through ordinary source/namespace mechanics after the initial seeded primitive universe.
  • Inert prelude declarations used before their implementing slice have explicit stubs and deterministic unsupported-use diagnostics.

Type System and Reflection

Source design:

Tasks:

  • Type-table snapshots cover primitive types, non-standard integer-width target diagnostics, optionals, enums, functions, structs, arrays, slices, ranges, pointers, contracts, dyn descriptors, and layout facts.
  • Reflection snapshots cover public names, wrong-kind diagnostics, visibility behavior, Type.Predicate propagation, structural satisfaction, conformance facts, and source/function/attribute/layout metadata.
  • Deferred reflection surfaces such as Type.Expr, Type.Value, namespace enumeration, and runtime value reflection have deterministic unsupported-use diagnostics.

Structs, Methods, References, Mutability, and Ownership

Source design:

Tasks:

  • Cleanup-state snapshots cover defer, early exits, live overwrite, double cleanup, hidden temporaries, loop-created iterators, and move with active defer.
  • Box allocation and failure-cleanup lowering is represented without backend access to source-level ownership rules.
  • Box(dyn C) descriptor, disposal, and upcast lowering is testable while public layout remains private.

Semantic Contracts and Dispatch

Source design:

Tasks:

  • Parser and sema snapshots cover contract(...) { ... }.
  • Parser and sema snapshots cover impl Type as Contract { ... }.
  • Diagnostics cover constrained local annotations such as *const impl Sequence(T) outside function declaration parameter position.
  • Diagnostics cover anonymous static impl pointer parameters outside function declaration parameter position.
  • Diagnostics cover coherence, visibility, contract operation method lookup, dependency upcasts, and intersection normalization.

Arrays, Slices, Ranges, and Indexing

Source design:

Tasks:

  • Array, slice, indexing, slicing, and range diagnostics have implementation snapshots.
  • Bounds-check lowering and trap behavior are represented in IR.
  • Slice descriptor field reflection is covered by sema/reflection snapshots.
  • Array/slice built-in contract conformances are covered by sema snapshots.

Loops and Iteration

Source design:

Tasks:

  • Dynamic iterator construction snapshots cover Box(dyn Iterator(Item)).create_from_dyn(I, alloc, value), erased allocator authority lifetime lint candidates, allocation failure cleanup, and no hidden allocation in for.
  • Loop-source diagnostics and hidden cleanup lowering cases are covered by implementation snapshots.

Attributes

Source design:

Tasks:

  • Attribute snapshots cover provider registration, target validation, repetition/conflict rules, provider evaluation, normalized metadata mutation, provenance reflection, and unsupported target diagnostics.
  • @resource, @repr(.catalyst), @align, @deprecated, ABI-named attributes, and accepted function call-convention metadata each have an owning slice and backend-facing fact path where needed.
  • Providers mutate compiler-owned targets only through explicit APIs and never patch AST directly.

C ABI Interop

Source design:

Tasks:

  • Exact diagnostics that reject unsupported export/import types are settled.
  • Resolved ABI, import/export, link-name, visibility, and lowered type facts are carried into SIR and IR.
  • C backend consumes only IR facts and does not inspect AST attributes or rerun semantic ABI checks.
  • Duplicate exported/imported link-name behavior is covered by diagnostics snapshots.

Realtime and Allocation Visibility

Source design:

Tasks:

  • Allocation-backed features make allocation authority explicit in SIR/IR snapshots and never hide allocation behind plain for or ordinary static dispatch.
  • Realtime/effect metadata remains explicitly out of V1 semantics, with any policy guidance implemented as warnings or future-lint classification rather than source validity.

Compiler Diagnostics and Lint Boundary

Source design:

Tasks:

  • Diagnostics snapshots cover payload shape, notes, warnings, lints, fatal errors, deterministic rendering, multi-file spans, and comptime-produced diagnostics.
  • Lint snapshots prove lints are hook/artifact-driven, can warn or fail only through explicit policy, and do not define source validity.
  • Lint configuration, suppression, and autofix remain explicitly deferred.

Standard Library Skeleton

Source design:

Tasks:

  • Standard-library smoke snapshots cover the accepted namespace skeleton and minimal declarations needed by V1 examples.
  • std.mem.FixedBufferAllocator and allocation-backed examples are staged through the allocator/Box slices, not preloaded as compiler magic.
  • Namespaces without V1 implementation stay as deterministic stubs or deferred diagnostics, not partially specified semantics.

SIR, IR, Lowering, and Backend Closure

Source design:

Tasks:

  • SIR can represent every V1 semantic fact without preserving source ambiguity or backend details.
  • IR can represent every V1 backend fact without unresolved names, generics, semantic contracts, or source-level method calls.
  • Layout finalization is routed through an internal representation-mode abstraction even though V1 accepts only .catalyst source layout.
  • Lowering rules exist for functions, errors, blocks, conditionals, loops, optionals, structs, arrays, slices, ranges, pointers, calls, methods, contracts, static dispatch, dynamic dispatch, Box, resources, attributes, and C ABI.
  • Lowering represents Allocator static dispatch, *dyn Allocator calls, Box private freeing state, dynamic contract pointer/dispose descriptors, placement initialization, and cleanup without backend access to source-level contracts.
  • IR verifier invariants are listed and tested.
  • C backend output is deterministic and inspectable for the V1 core.
  • Runtime traps, bounds checks, and checked safety failures have deterministic behavior and diagnostics/output expectations.
  • The backend never reaches into AST or SIR for facts that should be in IR.

V1 Test Matrix and Final Review

Source design:

Tasks:

  • Every V1 design workstream lists the phase snapshots needed to verify it.
  • Deferred V2/Far Future features that share syntax with V1 have deterministic rejection tests.
  • Example programs cover a scalar C export, module/import use, arrays/slices/ranges, resource cleanup, static contract dispatch, dynamic dispatch through Box(dyn C), and iteration.
  • git diff --check and a Markdown link/path check pass after documentation updates.
  • All V1 pages are accepted or explicitly marked as design-incomplete.

Implementation Discipline

Do not mix parser, sema, IR, and backend work unless the task is explicitly an integration milestone. Behavior changes need tests in the narrowest relevant phase and should follow the tracer-bullet TDD workflow in Testing. Snapshot output is part of the public contract, and generated output must remain deterministic.