Skip to main content

Module module_graph

Module module_graph 

Source
Expand description

L4 ModuleGraph — typed IR for a NixOS/nix-darwin/home-manager module system, compiled into worker/wrapper-split assignment closures with slice-keyed re-firing.

§Why this exists

Tvix has not staked out the module-system; cppnix re-runs the entire fixed point on every rebuild. The single biggest sui-vs-nix win on the rio sweep — 24 s on nixosConfigurations.rio.config. system.build.toplevel — lives here.

§Pipeline shape

AstGraph for each module .nix file (or .tlisp once dialect lands)
  → ModuleNode (declared options + config setter + import edges)
    → ModuleGraph (typed IR with dense ids + slice-keyed setters)
      → graph-hash cache key
        → compiled closure (defunctionalized setters, topo order)
          → fixed-point execution (Rayon per SCC, slice-keyed re-fire)
            → final config attrset
              → derivation graph

This module ships the typed IR + builder skeleton. The compilation pipeline (worker/wrapper synthesis, defunctionalization, NbE execution) lands in subsequent commits — the IR is its anchor.

§Invariants

  • Module ids are dense u32s, root module is always 0.
  • Every ImportEdge::target points at a valid module id.
  • ConfigSetter::slice lists every option path the setter reads. Empty slice = setter writes but doesn’t read config (a “leaf” setter; rebuilds only when its own source hash changes).
  • canonical_hash is the BLAKE3 of the rkyv archive bytes. Same module sources + same slices → same hash → cached compiled closure hits.

Structs§

ArchivedConfigSetter
An archived ConfigSetter
ArchivedEnvPrefixBinding
An archived EnvPrefixBinding
ArchivedImportEdge
An archived ImportEdge
ArchivedModuleGraph
An archived ModuleGraph
ArchivedModuleGraphHash
An archived ModuleGraphHash
ArchivedModuleNode
An archived ModuleNode
ArchivedOptionDecl
An archived OptionDecl
ConfigSetter
One config-setter fragment. The worker/wrapper-split shape is captured in the types: body_ast is the worker (computes the contribution); slice is the wrapper’s declared input projection (what the worker reads from config).
ConfigSetterResolver
The resolver for an archived ConfigSetter
EnvPrefixBinding
One env-prefix binding captured from a module’s outer wrapping. See ModuleNode::body_env_prefix.
EnvPrefixBindingResolver
The resolver for an archived EnvPrefixBinding
ImportEdge
One imports = [ ... ]; edge.
ImportEdgeResolver
The resolver for an archived ImportEdge
ModuleGraph
The compiled module graph.
ModuleGraphFixture
ModuleGraphHash
32-byte BLAKE3 hash. Same shape as the lockfile / AST graph hashes; kept separate so the type system distinguishes which graph kind a hash refers to.
ModuleGraphHashResolver
The resolver for an archived ModuleGraphHash
ModuleGraphResolver
The resolver for an archived ModuleGraph
ModuleNode
One module: the typed projection of one .nix (or future .tlisp) file’s contribution to the system.
ModuleNodeResolver
The resolver for an archived ModuleNode
OptionDecl
One options.foo.bar = mkOption { ... } declaration.
OptionDeclResolver
The resolver for an archived OptionDecl

Enums§

ArchivedEnvPrefixKind
An archived EnvPrefixKind
EnvPrefixKind
Distinguishes let-bindings (just bind name=value) from with-clauses (unpack the value’s attrset attrs as top-level names in the env).
EnvPrefixKindResolver
The resolver for an archived EnvPrefixKind
ModuleGraphError
Errors from the module-graph builder.

Constants§

CANONICAL_MODULE_GRAPH_FIXTURES_LISP
SCHEMA_VERSION
Bumped on every breaking change to the IR. Today: 1.

Functions§

load_fixtures
Load every authored fixture.

Type Aliases§

ModuleId
Dense module identifier. Root module is always 0.
SetterId
Dense setter identifier within a module. A module typically has exactly one setter (the function body), but mkMerge and mkIf constructs can split a logical setter into multiple typed fragments — the IR keeps them separate so each can be fired independently.