Semantics and typed HIR
The parser can tell that value * 2 is multiplication. Semantics determines which declaration value refers to, lands 2 as an i64, chooses checked signed multiplication, and records the overflow rule.
This is where Luce decides language meaning. Semantic analysis resolves names, types, methods, and failure handling. HIR carries those decisions through lowering so LLVM receives typed operations and control flow.
Why resolution and typing stay together
Resolving xs.append(value) needs the type of xs; typing the call needs the member that resolution found. Flow narrowing changes the type visible at a later expression; call selection changes the effect a containing function must handle. The implementation keeps these mutually recursive questions in one semantic stage, split into smaller concern modules.
Which declaration does this spelling denote? Is it visible? Has it been shadowed or used before initialization?
What exact representation flows here? Which member, conversion, return shape, or witness applies?
Is an optional narrowed? Does every path return? Can failure propagate? What must be released on each edge?
The two semantic spines
Analyzer
Collects modules, declarations, aliases, layouts, constants, signatures, interfaces, defaults, and the entry point. It settles the world in which bodies will be checked.
FunctionBuilder
Checks one body with scopes, narrowing, local state, temporary lifetime, receiver effects, and an HIR recorder.
Concern files provide small operations over those spines: calls.zig chooses a callable, assign.zig plans a place and replacement, closures.zig plans an environment, initializers.zig verifies class fields, and interfaces.zig constructs witnesses.
Checking and recording happen together
The check that chooses meaning records that choice immediately into typed HIR. A numeric literal gains its landed width. A method call gains its resolved target and receiver store behavior. A closure gains its capture kinds. An assignment gains its destination place and the releases that replacement requires.
Semantics records typed HIR. One recorder API captures the structured result. HIR lowering later assigns registers, builds basic blocks, places constants, and emits MIR instructions.
Rules checked from source structure
This is the only stage that can still explain a source mistake. It enforces immutable bindings, explicit numeric conversions, host access, class construction, interface conformance, recursive layout limits, closure cycles, worker sendability, return coverage, optional narrowing, and visibility.
| Rule | Source information used by the check |
|---|---|
A let binding receives one initialization | The declaration records the binding as immutable. |
| Worker-transfer graphs contain sendable value types | The static graph may contain a class transitively inside values and containers. |
| A public signature uses types visible at the same boundary | Visibility is a source-module relation erased before code generation. |
A stored closure uses a weak edge for a direct self cycle | The capture plan and destination relationship are clearest at the source expression. |
The result of semantic errors
Diagnostics are bounded and carry stable codes plus byte spans. When semantic errors exist, analysis returns the diagnostic set. A successful Analyzed value therefore contains resolved names and valid types, allowing later stages to focus on lowering and verification.