Compilation Pipeline
The IonPath compiler processes .ion files through a multi-stage pipeline. Each stage validates or transforms the schema, and errors are collected across all stages (the compiler does not stop at the first error).
Pipeline Stages
Stages execute in this order:
Parse
Lexes and parses all .ion files into an AST (Abstract Syntax Tree). The parser has error recovery — it continues parsing after syntax errors to report as many issues as possible in one pass.
ImportCycleDetectionStage
Detects circular #use imports. If module A imports B and B imports A, reports ION0001.
DuplicateSymbolValidationStage
Checks for duplicate type, message, service, or enum names within and across modules. Reports ION0002.
TransformStage
Converts the syntax AST into runtime IR (Internal Representation). Compiles messages, services, enums, flags, unions, and attributes into their typed objects. Performs first pass of type resolution — forward references are allowed.
StreamParameterValidationStage
Validates that each service method has at most one stream parameter. Reports ION0013 on violation.
RestoreUnresolvedTypeStage
Second pass of type resolution. Resolves all forward references. If a type cannot be resolved, suggests similar names using Levenshtein distance matching. Reports ION0009.
CircularTypeReferenceStage
DFS-based cycle detection in the type graph. If message A has a field of type B, and B has a field of type A, reports ION0030 with the full cycle path.
SchemaLockValidationStage
Compares the current schema against ion.lock.json. Detects breaking changes: removed fields, reordered fields, changed types, removed methods, etc. Reports ION0020–ION0029. Skipped with --no-lock.
Code Generation
Generates target code (C#, TypeScript) from the validated IR. Only runs if there are no errors. See C# Code Generation and TypeScript Code Generation.
Error Collection
The compiler collects all errors across stages rather than stopping at the first one. Each stage can set StopOnError to halt the pipeline after critical failures (e.g., circular imports make further resolution meaningless).
Diagnostics have three severity levels:
Verbose Output
Use --verbose to see timing for each stage:
$ ionc compile --verbose [ 2ms] Parse (3 modules) [ 0ms] ImportCycleDetection [ 1ms] DuplicateSymbolValidation [ 3ms] Transform [ 0ms] StreamParameterValidation [ 1ms] RestoreUnresolvedType [ 0ms] CircularTypeReference [ 1ms] SchemaLockValidation [ 5ms] CodeGeneration (dotnet, browser) ✓ Done in 13ms