v0.22.0—Bounded nullability checks and practical .NET migration guidance.See what's new

compile (default)

Compile Calor source files to C#.

Bash
calor --input <file.calr> --output <file.cs>

Overview

The default calor command (when no subcommand is specified) compiles Calor source files to C#. This is the core functionality of the Calor compiler.

Guard behavior since 0.15: with --verify, a clean, non-vacuous, assumption-free proven verdict drops its runtime guard by default. Pass --keep-proven-guards to retain otherwise-emitted guards and treat verdicts as diagnostic only (the 0.13/0.14 behavior). --elide-proven-guards is still accepted and now simply restates the default. Checks still require an enabled contract mode and supported runtime lowering; --contract-mode off emits none.


Quick Start

Bash
# Compile a single file
calor --input MyModule.calr --output MyModule.g.cs

# Short form
calor -i MyModule.calr -o MyModule.g.cs

# With verbose output
calor -v -i MyModule.calr -o MyModule.g.cs

Options

OptionShortRequiredDescription
--input-iFor compilationOne or more Calor source files; multiple files enable cross-module effect checks
--output-oNoOutput path for a single input; otherwise each .g.cs is written beside its input
--verbose-vNoShow detailed compilation output
--verifyNoEnable Z3 static contract verification
--keep-proven-guardsNoKeep every runtime guard even after Z3 proves a contract (opts out of the 0.15 default; verification stays diagnostic). Also spelled --no-elide-proven-guards.
--elide-proven-guardsNoDrop runtime guards on clean, assumption-free proven verdicts. This is the default since 0.15; the switch is kept so 0.13/0.14 command lines still work.
--analyzeNoEnable static analysis (dataflow, bug patterns, taint tracking)
--all-findingsNoReport all analysis findings including inconclusive results (requires --analyze)
--no-enforce-effectsNoOpt out of default-on effect enforcement
--strict-effectsNoPromote the "I cannot tell" effect warnings — Calor0411, Calor0419, Calor0425 — to errors
--permissive-effectsNoAssume a call the compiler cannot look up does nothing: Calor0411 and Calor0425 go unreported and Calor0410 becomes a warning. Never waives Calor0424, Calor0420, or Calor0421. This voids the effect guarantee — see Effects
--no-type-checkNoOpt out of the default-on type checker for this command
--cacheNoOpt into the incremental build cache for the default output layout
--no-cacheNoDisable verification and incremental-build caches
--clear-cacheNoClear verification and incremental-build cache state first
--contract-modeNoRuntime contract mode: off, debug, or release (default debug)
--verification-timeoutNoZ3 budget per contract in milliseconds; default 5000
--strict-apiNoRequire breaking-change markers for public API changes
--require-docsNoRequire documentation on public functions and types
--no-strict-bind-inferenceNoOpt out of default-on Calor0251–Calor0253 inference checks
--experimentalNoEnable a named experimental feature; repeatable
--format-fNoDiagnostics: text, json, or sarif
--no-telemetryNoForce-disable telemetry; telemetry is opt-in and already off by default

Output Convention

The recommended convention for generated C# files is the .g.cs extension:

Plain Text
MyModule.calr → MyModule.g.cs

This indicates "generated C#" and helps distinguish Calor-generated code from existing C# in your project.


Error Reporting

When compilation fails, errors are reported with file location:

Plain Text
Error in Calculator.calr:12:5
  Undefined variable 'x' in expression

  §R (+ x 1)
       ^

Compilation failed with 1 error

For machine-readable diagnostics, use --format json|sarif or the calor_check MCP tool. See Structured Output.

Nullable receiving boundaries

In Calor 0.22, Calor0272 (initialization), Calor0273 (native return), and Calor0274 (method argument) are Errors on the supported receiving shapes. They stop compilation with exit 1 before C# output is emitted. Use a fresh output path when reproducing a failure; an old output file is not evidence of successful compilation.

--no-type-check, CALOR_NO_TYPE_CHECK=1, --no-strict-bind-inference, effect controls, and --transpile-only do not disable these binding errors. Verification and runtime-contract settings do not waive them. This is not whole-program null safety. See Nullability and .NET Interop for complete rejected/safe examples, supported shapes, and the exclusions for mutable assignment/rebinding and constructor inputs.


When One File Fails

Changed in 0.16. This affects calor on the command line and dotnet build alike.

The compiler checks the C# it generates by handing it to Roslyn — Microsoft's own C# compiler — and if Roslyn rejects it, that is Calor1002. The catch is that a file which failed to compile leaves the types it was supposed to declare missing, so every other file that mentions one of those types now fails to build too — not because anything is wrong with it, but because a piece it needs was never produced. Those follow-on failures are noise. They hide the one real error underneath a pile of Calor1002s that vanish as soon as you fix it.

From 0.16 the compiler works out which types the failed file was going to declare, and skips the Roslyn check only for the outputs that mention them. Everything else is still checked, so a genuine Calor1002 in an unrelated file is still reported.

The outputs it skipped are treated as unfinished, not as fine:

  • no .g.cs file is written for them,
  • no entry goes in the build cache, so the next build redoes them rather than trusting a result that was never checked,
  • and the build does not claim they compiled successfully.

Two edges are worth knowing. If a file is broken badly enough that the compiler cannot work out what it declares — an unterminated string or a stray marker, rather than an ordinary syntax error, which keeps enough structure to be scoped — then nothing is written for that run at all, which is the safe answer rather than the convenient one. And --transpile-only is exempt: it already opts out of the Roslyn check, so it can still write output when compilation has no earlier errors. It does not bypass active binding errors.

Neither surface did any of this before 0.16, and both now apply the same rule from the same code, so neither reports cascade errors the other does not. They are not identical in general: dotnet build hands Roslyn the rest of your project's C#, its assembly references, its analyzers and its Nullable and TreatWarningsAsErrors settings, and calor on the command line hands it none of that — so the two can still reach different verdicts on the same file for reasons that have nothing to do with cascading.


Integration with MSBuild

For automatic compilation during dotnet build, use calor init to set up MSBuild integration.


Exit Codes

CodeMeaning
0Compilation successful
1Missing input, invalid option combination, missing file, or compilation failure

Static Contract Verification

Use --verify to enable Z3 static contract verification:

Bash
calor -i MyModule.calr -o MyModule.g.cs --verify

The compiler uses Z3 to attempt proving contracts at compile time and reports one of seven verdicts. Since 0.15, a clean proven postcondition drops its runtime guard by default; other verdicts never authorize proof-based removal. Pass --keep-proven-guards to retain otherwise-emitted guards and use verification as a diagnostic only. --contract-mode off emits no checks, and enabled checks still require supported runtime lowering.

Example output:

Plain Text
Compiling MyModule.calr...
  Function Square: PROVEN - Postcondition (result >= 0)
  Function Divide: ASSUMED - Postcondition (result >= 0)
Generated MyModule.g.cs

The seven statuses are proven, refuted, assumed, unknown, timeout, unsupported, and unavailable. Only a clean, non-vacuous, assumption-free proven postcondition is eligible to lose its runtime guard — and --keep-proven-guards prevents that proof-based removal. See Verification Guarantees.


Verification Caching

When using --verify, the compiler caches Z3 verification results to avoid redundant solver work. The separate incremental-build cache is opt-in for a plain compile with --cache; calor watch enables it by design. Incremental caching is available only for the default output layout, not a redirected single --output.

Cache Options

Bash
# Default: caching enabled
calor -i MyModule.calr -o MyModule.g.cs --verify

# Disable caching (useful for CI or debugging)
calor -i MyModule.calr -o MyModule.g.cs --verify --no-cache

# Clear cache before verification
calor -i MyModule.calr -o MyModule.g.cs --verify --clear-cache

# Opt into whole-file incremental build caching (default output path)
calor -i MyModule.calr --cache

See Also