Skip to content

Diagnostics

Stable codes, source attribution, layer ownership, recovery, and build gates.

Updated View as Markdown

Diagnostics are the compiler’s public failure protocol. Every expected problem in source or configuration should become a structured diagnostic rather than a panic, silent fallback, or untyped string.

Diagnostic record

A diagnostic carries:

Field Purpose
Stable code Machine-readable identity such as ATOLL2002
Message Short user-facing description
Severity Error, warning, info, or hint
Primary range The main source span
File Source file that owns the primary range
Labels Related spans, including cross-file spans
Help Explanation or next action
Suggestion One or more concrete text edits
Causes Trace event IDs that contributed to the conclusion

The stable code is not the complete message. Tests and tools can branch on the code while the message, labels, and help improve without breaking protocol consumers.

Code ranges

The current catalog uses broad numeric families:

Range Main category
ATOLL1xxx Parse and source-form errors
ATOLL2xxx Resolution, checking, decorators, and related semantic errors
ATOLL3xxx Type, trait, and semantic-shape errors
ATOLL4xxx Effects, capabilities, unsafe operations, and some IR safety checks
ATOLL5xxx Backend and code generation
ATOLL6xxx Monomorphization
ATOLL7xxx Performance and optimization hints

Removed codes leave gaps. Reassigning an old code to a different meaning would break editor filters, CI rules, documentation links, and snapshots.

Numeric families are a default classifier, not perfect provenance. MIR can produce a pointer-safety ATOLL4xxx or backend-boundary ATOLL5xxx diagnostic. When a caller knows the producing stage, it must tag that stage explicitly.

Layer ownership

DiagnosticTable aggregates entries with one of these producer layers:

  • Parse
  • Sema
  • Mono
  • IR
  • Codegen
  • Driver

Ownership answers “which stage established this failure?” A semantic type-mismatch code emitted defensively during specialization still belongs to Mono if specialization discovered it. Conversely, a blended backend result may require code classification when the original stage tag was not retained.

New code should preserve explicit producer layers at aggregation boundaries rather than relying on code ranges after vectors from several stages have been mixed.

Source attribution

Internal ranges use byte offsets. A diagnostic also identifies its source file, allowing the language server to partition project diagnostics by document. Secondary labels can point into another file, which is necessary for cross-module declarations and prelude signatures.

Compiler-bundled core source creates a presentation problem: an error may be detected inside a stub even though the actionable code is a user call. The default user path redirects an internal primary frame to a suitable user-facing label. --show-internal disables that redirection for compiler development.

Redirection changes presentation, not ownership or the underlying source facts. Tests for an internal failure should cover both views where relevant.

Severity and gates

Severity controls the pipeline:

Severity Build effect
Error Blocks the next artifact-producing stage
Warning Build may succeed; indicates a likely defect
Info Non-blocking explanatory information
Hint Non-blocking style, migration, or optimization guidance

atoll check returns parse and semantic diagnostics without emitting code. atoll build stops before specialization when analysis has errors, before codegen when Mono has errors, and before artifact writing when IR or codegen has errors.

The artifact writer rejects a unit result that carries diagnostics requiring failure. A successful build must not leave a partially valid collection of unit files that looks complete.

Recovery and suppression

Parser recovery allows multiple diagnostics from one file, but later stages should avoid cascades that add no information. An explicit syntax-error node or sentinel type can contain damage while independent declarations continue.

Good suppression is local:

  • report the unknown symbol once, then avoid derivative method failures on its error type;
  • report the malformed pattern, then keep checking other match arms;
  • report a missing backend layout at its source origin, then stop lowering that unit.

Suppression must not hide an independent problem or allow emission through a known error.

Suggestions

A suggestion is an ordered set of source replacements with a user-facing title. It should be auto-applicable only when:

  • every edit range belongs to the intended source snapshot;
  • the edit has one unambiguous interpretation;
  • applying all edits yields syntactically meaningful text;
  • no hidden project knowledge is required.

Help text is more appropriate when several repairs are possible.

Provenance

Diagnostics can carry compile-story event IDs. A type mismatch can therefore refer to the inference, coercion, or dispatch events that established its conflicting facts. This supports “why” tooling without expanding every ordinary CLI message into a trace dump.

Provenance is optional side data. A diagnostic remains valid and renderable when tracing is disabled.

Adding a diagnostic

  1. choose the stage that owns the violated invariant;
  2. add a new stable code in the appropriate catalog range;
  3. select the narrowest useful primary range;
  4. attach labels for the expected declaration or competing source fact;
  5. add help or a suggestion when the repair is known;
  6. tag the producer layer explicitly at aggregation;
  7. add positive, negative, range, message, and recovery tests;
  8. verify CLI and LSP rendering for multi-file cases.

A panic remains appropriate for an impossible internal state already guarded by a verifier. A user-reachable unsupported feature is not such a state.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close