Architecture

Sage is a demand-driven Rust semantic frontend. Its architecture is rooted in symbols: stable identities for definitions. Parsing and expansion create local symbols, resolution discovers symbols, checked types and Typed IR refer to symbols, and symbol-keyed Salsa queries compute semantic details only when a consumer asks for them.

This page is the maximally zoomed-out map. Follow a phase chapter to understand a source-to-output transformation, or a subsystem/representation chapter to understand a facility shared across transformations.

Design tenets

The complete list is in Tenets. The architectural consequences most visible in the pipeline are:

  • Stable semantic identity comes before semantic detail. A symbol identifies a definition; signatures, members, fields, and bodies are separate lazy queries keyed by that identity.
  • Queries expose semantic boundaries. A consumer requests the narrowest stable result it needs, such as one signature or one body, rather than an eagerly checked crate.
  • Bodies depend on interfaces, not other bodies. Checking a call may read a callee signature and trait metadata but must not read the callee body.
  • Completed bodies are elaborated. The body-checking output is the tree-structured Typed IR, not source syntax plus adjustment side tables.
  • Incremental dependencies are architectural. The key and fields of each query determine which edits may cause downstream work to execute again.
  • Conformance is exact. Sage and rustc independently emit a shared oracle representation; the adapters are thin and comparison is textual identity.
  • Semantic evidence starts from source. Integration tests run checked-in Rust projects through the production layers under review; snapshots record results but never replace semantic computation.

crates.sage_ir.crate.identity_before_detail

Verification scenarios: Identity tests and edit experiments show that an unchanged definition retains the same symbol when unrelated or detail-only inputs change, while symbol-keyed detail queries execute only when their own observed inputs require it.

crates.sage_ir.crate.narrow_demands

Verification scenarios: Focused query traces state required and forbidden dependencies for representative module, signature, and body requests, including an explicit no-callee-body assertion.

Symbols connect the pipeline

A path such as crate::parse::Parse::next is a way to find a definition. It is not the definition's identity. Resolution maps syntax, names, and namespaces to a symbol. Later phases use the symbol itself as their key:

LocalFnSym::sig(db)
LocalFnSym::body(db)
LocalTraitSym::items(db)
TraitSymbol::sig(db)

Local symbols are Salsa tracked identities created from parsed or generated items. External symbols are compact handles for definitions supplied by dependency metadata. Symbol erases the item kind when a heterogeneous list is needed; FnSymbol, TraitSymbol, ModSymbol, and the other kind-specific wrappers recover the static distinction required by semantic operations.

The Symbols and Semantic Identity chapter defines this model and its current incremental guarantees.

Rust compilation pipeline

The pipeline is layered but not a mandatory batch sequence. Asking for one function body walks only the dependencies needed for that body. Asking for a module outline can stop after expansion.

flowchart TD
    Source[SourceFile input] --> Parse[Parse and create local symbols]
    Parse --> Expand[Expand one module]
    Expand --> Resolve[Resolve names to symbols]
    Resolve --> Sig[Check one item signature]
    Sig --> Body[Check and elaborate one body]
    Body --> Typed[Completed Typed IR]

    Metadata[External metadata] --> Resolve
    Metadata --> Sig
    Metadata --> Solver
    Resolve --> Body
    Infer[Type inference] --> Body
    Solver[Trait solver] --> Body
PhaseGranularityDirect inputSuccessful outputPrimary entry boundary
Parse and create symbolssource-backed moduleSourceFile, module scope, editionordered unexpanded item symbols with per-item CST and provenanceunexpanded_items(db, module)
Module and macro expansionlocal moduleunexpanded item symbols and macro-resolution environmentcomplete ordered direct expanded item symbolslocal_expanded_module_items(db, module)
Signature checkingone definitionsymbol, its CST or external metadata, referenced signatureschecked signature and parameter environment under a bindersym.sig(db) and kind-specific metadata queries
Body checking and elaborationone function or associated functionbody CST, its signature, referenced interfacescompleted CheckedBody containing elaborated Typed IR or diagnosticsLocalFnSym::body(db)

The phase contracts are described under Rust Compilation Pipeline. A phase can terminate without its successful guarantee because of user errors, unsupported Sage functionality, unavailable external facts, or a resource limit. That is terminal incompleteness, not work that more polling will finish.

crates.sage_ir.crate.terminal_incompleteness

Verification scenarios: Each phase with an incomplete outcome tests its reason and surviving guarantees, and proves that repeating the same demand without an input or limit change cannot silently upgrade it to complete.

Semantic subsystems

These facilities are invoked from multiple phases:

SubsystemSemantic responsibilityTypical granularity
Name resolutionmap paths and names in a namespace and scope to symbols; retain ambiguity or incompletenessone path/name lookup
Type inferencerelate types transactionally, defer constraints, and finalize a body with no live inference workone body, with isolated speculative versions
Trait solverprove a fixed trait goal or normalize an input alias while preserving canonical query semanticsone canonical solver goal
External metadataexpose authoritative owned facts about reachable dependency definitions without asking rustc to solve Sage goalsone keyed external definition or lookup

See Semantic Subsystems. Subsystems do not define additional source-to-source phases merely because their implementation uses tracked queries.

Representations and infrastructure

ConcernRole across the pipeline
Symbolsstable local and external definition identity and symbol-keyed semantic operations
Typed IRfully resolved, tree-structured output of completed body checking
Stashcompact ownership and hash-consing for CST and semantic trees at query boundaries
Spanssource and expansion provenance with relative locations inside an item
IncrementalitySalsa inputs, tracked identities, interned leaves, and tracked functions that record observed dependencies

Temporary inference state, method candidates, and partially checked expressions remain inside the body query. They are not public incremental boundaries merely because they are important steps in the algorithm.

Validation and inspection

The architectural pseudocode in md/design/crates/ offers a symbol-and-method view with checkable dependency envelopes. Its initial model summarizes the central demand graph. sage-meta is the shared build and validation layer for Markdown specifications, .sage models, and Rust: it checks source correspondences and named rules' test references and provides the runtime contract engine. The committed review checklist records reviews of claims and their associated test bodies; the shared checker rejects missing or stale decisions. Its public check runs in CI and workspace Cargo tests. Model consistency, source coverage, and observed runtime conformance remain separate claims.

The architecture is meant to be reviewable at increasing depth:

  1. A chapter states its destination contract.
  2. Generated anchor pages connect each claim to its implementation, focused tests, saved review, and explicit TODO/N/A gaps. Test sources and reviews remain distinct from observed execution and trace evidence.
  3. Current limitations belong in those implementation/test entries. Earlier observations remain in the deviation history; new changes record their reasoning and plan in scoped RFDs.
  4. Anchored excerpts lead from the explanation into the load-bearing code.
  5. The Oracle Test Harness establishes exact conformance for pinned semantic slices.
  6. The Semantic Inspector exposes readable semantic output and structured query traces from a persistent workspace.

See Validation and Inspection.

Code map

The semantic structure above maps to the current workspace as follows:

PathResponsibility
crates/sage-ir/src/parse/ and cst/parse source and retain per-item concrete syntax
crates/sage-ir/src/local_syms/local tracked symbols and their signature/body/member queries
crates/sage-ir/src/symbol/erased and kind-specific local/external symbol wrappers
crates/sage-ir/src/check/resolve/lexical and module-level name resolution
crates/sage-ir/src/check/infer/transactional inference, deferred constraints, and obligation lifecycle
crates/sage-ir/src/check/solve/canonical positive trait proof and alias normalization
crates/sage-ir/src/tytree/completed typed body representation
crates/sage-ir/src/tcx/ and external_syms.rstyped external metadata boundary and tracked lowering
crates/sage-stash/stash storage and hashing infrastructure
crates/sage-inspector/, crates/sage-reflect/, and src/inspector.rstyped inspection service, protocol, structural reflection, and live semantic provider

Implementation and test evidence

The generated anchor pages report implementation entries, annotated tests, explicit TODO/N/A gaps, and saved claim/test reviews. These associations do not themselves establish that a test ran.

The earlier coverage snapshot preserves the former capability descriptions, edit experiments, and limitations as historical evidence. Current coverage comes from the generated entries; implementation plans and decision rationale belong in the relevant RFDs.