- Read
design.mdbefore making code changes. It is the forward-looking design reference for checked modules, the post-check IR pipeline, LIR, ARC, backends, LirImage, and compiler invariants. - Follow
docs/langref-style-guide.mdwhen writing or editing anything indocs/langref/. - Workarounds are categorically forbidden in this code base.
- Fallbacks are categorically forbidden in every stage of compilation other than specifically parsing and error reporting.
- Heuristics are categorically forbidden in every stage of compilation other than specifically parsing and error reporting.
- Every compiler stage other than specifically parsing and error reporting must consume explicit data produced by earlier stages rather than trying to recover, guess, reconstruct, approximate, or "best effort" its way to missing information.
- A compiler invariant (an assumption that can fail only if the compiler has a bug) is handled the same way everywhere in the compiler, every stage included: a debug-only assertion in debug builds, and
unreachablein release builds. Never add release-build runtime checks, panics, error returns, or recovery for compiler invariants. User-facing failures (bad source, type errors, missing files, allocation failure, corrupt caches) are not compiler invariants and are reported or propagated, never asserted. See design.md. - Environment variables: add a developer-diagnostic environment variable whenever one helps. It must be a member of
base.dev_diagnostics.Varand be read only throughbase.dev_diagnostics(see design.md "Developer Diagnostics"), so only Debug and-Ddev-diagnosticscompilers read it. Adding any environment variable that a release compiler reads, or making an existing developer-diagnostic variable available in release builds, is FORBIDDEN without explicit and unambiguous approval from Richard Feldman (rtfeldman). Approval must name the specific variable; never infer it from a task, an issue, a design note or an existing pattern. If a change seems to need one, stop and ask. - Backends are categorically forbidden from thinking about reference counting in any way other than specifically dumbly following the explicit LIR
increfanddecrefstatements emitted by earlier compilation steps. - Never use JSON anywhere in the compiler except the LSP, whose protocol requires it. Data the compiler reads or writes gets a bespoke, simpler format instead, like the package dependency sidecar (
src/compile/package_resolution.zig) and theroc installmanifest (src/cli/install.zig). Where users need machine-readable output from roc, offer a Roc plugin instead, asroc gluedoes. - Fuzzers must generate small typed language constructs and compose them randomly. Do not add catalog-style fuzzers made from handwritten scenario emitters.
- When
zig build minicifails in one section, fix the issue and rerun that specific failing section until it passes. Only return to the fullzig build miniciafter the targeted section passes, so the full run is used to find the next failing section rather than as the inner retry loop. - Never add a probe-then-mutate rewrite to the checker (a structural probe over solved types whose result gates a mutation of the solved graph or of stamped dispatch-plan metadata) without a rule declared in design.md's "Solver-Mutating Rewrites" section. Such a rewrite is indistinguishable at review time from a change to the language's typing rules, so the rule must be declared first, the rewrite named for it, and both its accepted and rejected sides pinned by tests.
Store.dangerousSetVarRedirectenforces this by signature: every call site cites aRedirectRulemember, and new members require a design.md declaration. Review checklist: a diff that adds aRedirectRulemember, callssetVarContent/dangerousSetVarDescoutside the inventoried sites, or restamps CIR plan metadata must update the design.md Rewrite Inventory in the same change.