Expand description
Cross-file semantic analysis for inkle’s ink narrative scripting language.
The analyzer merges per-file SymbolManifests from brink-ir into a
unified SymbolIndex, then runs validation passes (name resolution,
duplicate detection, type checking). Both brink-compiler and brink-lsp
consume the analysis result.
Structs§
- Analysis
Options - Tooling options for analysis: the registered host manifest and the severity policy for its external checks. Defaults to no manifest.
- Analysis
Result - The output of cross-file semantic analysis.
- Analyzer
Tables Owned - Owned form of
brink_ir::lir::AnalyzerTables(issue #1527) — every analyzer side-table LIR lowering reads, held by value instead of by the borrowed referencesAnalyzerTablesitself carries. A caller builds one of these (viaassemble_analyzer_tables) and then borrows its fields into anAnalyzerTablesat the lowering call site, exactly asbrink-db’s two salsa queries already borrow their own ownedUfcsLookup/CoalesceLookuplocals. - Body
Types - The full inferred picture of one def’s body: params, every local
(params ∪ temps) by name, and the return type. A superset of
InferredSig—signaturesis the firewall-facing projection,bodiesis what a hover/diagnostic consumer (TM-5) wants. - Call
Graph - A directed call graph over inferable definitions.
- Coalesce
Chain - Every step of one
or-coalescing chain, innermost first. - Coalesce
Step - The recorded types of one
orstep, in the left-associative order the grammar builds. - CueHarvest
- One
@NAMEcue’s harvest record: every occurrence project-wide, in no particular merge order (a completion consumer sorts as it needs). - Def
- One inferable definition: its own id, declaring file, declared params, and body.
- Direct
Call ArgMismatch - One statically-checkable argument-type mismatch recorded at any of
three producer sites whose callee resolves straight to a known def via
known_sigs— so its declared parameter types are already fully known at the site — unlike the T1c call-through-a-value caseValueCallFactexists for: - Effect
Atoms - The raw per-definition atoms harvested from one body walk — the inputs the
solve_scc_effectsfixpoint closes over.reads/writes/callsare the direct atoms this body emits;direct_callsare the inferable (knot/stitch) callees whose rows must be joined in transitively;creates_fn_valuesare the targets this body creates fn values for (Fork A, issue #1726 — structural, fed into the call graph alongsidedirect_calls);opaquerecords that the body performed a call through a function value whose reaching values were not all created in-project (or another effects-opaque construct), forcing the pessimal floor. - Effect
Row - A static summary of the atomic effects a definition (and everything it
transitively calls) may perform — the spec §2 “row”. Unordered sets over a
finite per-project lattice, so
joinis a monotone least-upper-bound and the per-SCC fixpoint terminates without widening. - Field
Assign Mismatch - One statically-checkable type mismatch at a dotted struct-field
assignment target (issue #1900, split from #1864/#1877 — PR #1899’s own
check_declared_assign_targetexplicitly excludes a multi-segment target, since a dotted target’s declared type is its root’s shape, not the field’s). - FileId
- Opaque identifier for a source file within a multi-file project.
- FnRow
- The effect row riding a
Ty::Fn—docs/effects-spec.md§5 (“rows ride the unifier — the heap answer”), issue #1680 step 3. - Harvest
Index - The project-wide harvest index (issue #2114): every
@NAMEcue payload and every inline-markup span kind/attribute name, keyed by name so completion crosses files — the compiler-side sibling ofcrate::SymbolIndex. - Harvest
Names - Range-free completion projection of a
HarvestIndex(issue #2134). - Harvest
Site - One occurrence of a harvested name — lets a completion consumer answer “where is this used”, not just “does this name exist”.
- Import
Scope - Per-file import context threaded into resolution (M-2d, docs/modules-spec.md §2; issue #790) so a bare reference with multiple cross-module candidates binds to the module this file actually imports — “names cross module boundaries only via import” — rather than to the flat duplicate-winner.
- Inference
Result - The whole-project inference result (mirrors
AnalysisResult’s shape: one pure function over already-computed inputs, callable directly or wrapped as a salsa query). - Inferred
Sig - A def’s inferred signature: positional param types (declaration order) plus a return type. The generalized, per-def result of a body’s fixpoint solve — what a caller reads (never the caller reading the callee’s body directly; that’s the firewall).
- Lambda
Annotation Mismatch - One incompatibility between a lambda’s own written annotation (a
param’s
: Tor the lambda’s: Rreturn annotation) and its body-derived type (issue #1994, RULED 2026-08-01, closing #1932: “the written annotation takes priority… an incompatible body is an eager error at the lambda, not a deferred surprise at the call site”). - Lambda
Escape Slot - One lambda-body param or body-declared temp, ready for the same
Unknown-escape (
E065) / Conflicted-escape (E066) treatmentstrict::check_defalready gives a top-level def’s ownparams/locals(issue #1770: “lambda bodies are invisible to strict-mode escape checking… give lambda bodies a per-lambda frame”). - Lint
Policy - The resolved
[lints]policy (issue #1160): per-code severity overrides plus the blanketdeny-warningsflag. Bundled as its own small, cheaply-PartialEq-comparable value — rather than as two loose scalars — sobrink-db’s severity-partitioning call sites can share one narrow salsa projection the same wayTypePolicyalready does (seebrink-db’stype_policy_query/lint_policy_querydoc comments for the cutoff argument). - NodeKey
- Identity of one HIR node for side-table purposes: the file it lives in plus its source range.
- Project
Config - Protocol
Impl Decl - One protocol impl registration: “
functionimplementsprotocolfor the declaredSTRUCTnamedtype_name”. Programmatic v1 (see the module doc) — the future source spelling lowers into this same shape. - Resolved
Module - A file’s resolved module (M-1, docs/modules-spec.md §1/§5).
- Resolved
Param - A merged parameter: name (from the ink declaration) and resolved type.
- Resolved
Type - A resolved type reference: the written name, its base type (if resolvable), and any closed-domain constraint (from a semantic type definition).
- SccGraph
scc_graph’s output: the dependency-ordered component membership plus the condensation DAG’s adjacency, keyed by each component’s stable id — its own minimum member (FG-2, issue #631’sscc_membership()query;SccIdis a plainDefinitionIdinbrink-db’s query layer, per the design doc’s “already the sort key in graph.rs” note).- Shape
Info - One declared struct shape: fields in declaration order, name -> declared
type (
Ty::Unknownif the field’s own annotation doesn’t resolve — e.g. an unrecognized type name, already flagged elsewhere byannotations::check’sE061). - Shape
Table declared_shapes’ referrer-scoped lookup table — see that function’s doc for the coexistence story this exists to resolve correctly.- Side
Table - A
(node → payload)side channel: analysis verdicts recorded beside the HIR rather than written into it (D2 — the HIR stays immutable). - Sig
- Per-declaration signature summary (phase-0 stub).
- Span
Harvest - One markup span kind’s harvest record.
- Span
Names - One markup span kind’s range-free completion record — see
HarvestNames. - Symbol
Meta - Per-symbol merged metadata (docs, types, values), surfaced to the IDE and
used by the call-site checks. Keyed by the symbol’s
DefinitionIdon theAnalysisResult. For externals this merges inline docs with the registered host manifest; knots/stitches carry inline docs only; VAR/CONST add an inferred initializer value. - Typed
Assign Mismatch - One statically-checkable type mismatch at a declaration-initializer or
assignment site against an already-known declared type (issue #1877) —
the
~ temp/plain-assignment sibling ofDirectCallArgMismatch, which covers only direct-call arguments. - Ufcs
ArgMismatch - One statically-checkable argument-type mismatch at a UFCS-desugared free
function call (
recv.name(args)→name(recv, args)) — issue #1881, the UFCS sibling ofinfer::DirectCallArgMismatch(#1864/PR #1875, direct calls) andinfer::TypedAssignMismatch(#1877/PR #1899, declaration initializers and assignments). Reported by [check_strict] asE063, the same code the other two siblings use — no new code minted for this position (docs/t1c-spec.md §8’s “existing TM-3 machinery” posture, extended here rather than a parallel checker). - Ufcs
Call Args - One UFCS-desugared call site’s (
recv.name(args)→name(recv, args)) written-argument types (issue #1881) — the receiver itself is not included here (its type is already known directly toufcs::UfcsVisitor, this fact’s sole consumer, from receiver-type resolution). Recorded unconditionally at every multi-segment, value-resolving call this pass walks (seebody::InferPass::infer_call’s own doc for why it cannot check anything against a UFCS receiver directly) — this is the raw per-argument type databrink_analyzer::ufcs’s own resolution pass needs to complete its own argument-type check against the desugared free function’s already-known declared param types (InferenceResult::signatures, keyed by the target), without a second expression-type inference pass over the same body. - Value
Call Fact - One statically-checkable fact about a call through a function value
(T1c, docs/t1c-spec.md §4 — “under
types = strict, calls through function values are statically checked”). - Value
Meta - Initializer-derived metadata for a VAR or CONST declaration. Purely presentational — ink variables are dynamically retyped at runtime, so this never drives diagnostics.
Enums§
- Coalesce
Error - Why an
coalesceapplication is ill-typed (NS-A1, F19). - Coalesce
Shape - Which of
infer::ty::coalesce’s three outcomes oneorstep took — the shape question LIR lowering asks, answered from types instead of syntax. - Dialect
- Compiler dialect: gates T1b brink-extension syntax. Default
StrictInk— divergence from the oracle-anchored ink subset is a visible, one-time, per-project choice (docs/t1b-surface-spec.md §1). - External
Check Severity - Severity policy for manifest-driven external checks. Configurable as a
compiler/IDE flag; defaults to
Error(a registered manifest is binding). - Inferred
Type - The type of a VAR/CONST initializer literal. Deliberately separate from
the host-manifest
BaseTypevocabulary —Divert/Listare ink runtime concepts that must not leak into the manifest serialization schema. - Lint
Level - A
[lints]table entry’s severity (issue #1160) — mirrors Rust’s own[lints]levels.Warnis every diagnostic code’s implicit level when[lints]doesn’t mention it, so it doubles as this type’sDefault. - Protocol
- One entry of the closed protocol registry (stdlib-spec §9.6). The enum is the registry: adding an entry is a compiler change by construction.
- Semantic
Type Diagnostic Severity - Severity policy for unknown-semantic-type diagnostics (
E040), parallel toExternalCheckSeverity. Configurable as a compiler/IDE flag; defaults toTolerant— the #339/#527 default-tolerant path, where an unresolved semantic type is only diagnosed once aHostManifestis registered. Raising it toErroropts back into strict checking (E040fires for any unresolved type even with no manifest registered) — e.g. so a host can catch typo’d semantic-type tags before wiring up a full manifest (#532). - Ty
- A type in the checker’s universe (typed-mode-spec §2).
- Type
Policy typesproject policy (docs/typed-mode-spec.md §1).Gradualis the pre-flip behavior —Unknownunifies with anything, annotations are optional seasoning, and the strict checks do not run.Strictrequiresdialect = brink.- Ufcs
Verdict - What one
recv.name(args)call site resolved to (D2’s “node → resolved target”). Consumed by LIR lowering — which of the two code shapes to emit — and by IDE hover/go-to-def, which needs the real target rather than the receiver theResolutionMaprecords for the callee path. - Value
Call Kind - What a
ValueCallFactobserved. Strict mode maps these onto the existing TM-3 machinery — escape codes for unresolved callees, the typed-mismatch code for known-type disagreements — rather than minting parallel codes (docs/t1c-spec.md §8).
Functions§
- analyze
- Run cross-file semantic analysis with default options (no host manifest).
- analyze_
with_ options analyzewith explicit tooling options — same test-fixture status and same deliberately absent module/nativeness parameters (seeanalyze).- annotation_
mismatches - Compare each def’s annotated param/return types (
Sig, declaration-only) against the same def’s body-inferred types (InferenceResult, frominfer_project/the composedcall_edges→solve_sccpath) and report a disagreement. Advisory-only (E063is a warning) — severity policy for strict mode is TM-3’s call, not this one’s. - assemble_
analyzer_ tables - Assemble every analyzer side-table LIR lowering needs, from scratch, in one whole-project pass — the one path a caller with no salsa layer of its own must use (issue #1528).
- assignable
- Is a value of type
sourcelegal in a slot declaredtarget? - await_
condition_ callees - Every
DefinitionIdcalled (directly) from anyawaitcondition inhir, resolved throughresolutions. The salsa path (brink-db‘sawait_purity_diagnostics_query) uses this to fetch exactly those defs’ memoized per-def effect rows — the incremental analogue of the monolithic path handingcheckthe whole-projectcrate::infer::effects_projecttable. A callee that resolves to a non-inferable symbol (anEXTERNAL, a VAR fn-value) simply has no per-def row;checkhandles it via the same resolution it does here, so the two paths agree. - await_
purity_ diagnostics - Check every
awaitcondition inhiragainst the whole-project effect rowsrows(docs/flow-suspension-spec.md §3/§5). Returns anE105for each condition that is not effect-free (read-only). - call_
edges - Pass 1, exposed per one definition (FG-2, issue #631 —
call_edges(def)). Computes exactly what [build_call_graph]’s loop body computes for one def: infer this def’s body withknown_sigsempty (every call resolvesUnknown; only the set of resolved call targets is kept, matching the design doc’s explicit “keep reusinginfer_def_bodyand discard types, as today” allowance for this query). Returns an empty set for an unknown/non-inferable def id — same “absent data reads as empty, never panics” contract as the rest of this module. - call_
site_ metas - Project the external-kind entries of an enrichment map to a name-keyed
map for the call-site checks (issue #750 / FG-3 completion). Range-free
by construction (
SymbolMetacarries no spans), sobrink-dbcan put anEq-cutoff memo between the (often-invalidated, full-ranged-index- reading) enrichment pass and every file’s call-site walk — theresolution_indexplaybook. - check_
annotations - Semantic diagnostics on annotation content: unknown type names (
E061). Brink-dialect-only (see module doc).manifest: the registered host manifest, if any — T1d-2’sHandle<K>vocabulary source (Nonedegrades to an empty handle-kind set, same posture as every other manifest-driven check). - check_
anonymous_ stateful - Run the lint over one already-lowered file’s
HirFile. Bothlower_file(ink) andlower_native_file(native) inbrink-dbcall this per file — see the module doc’s “Wiring” section. - check_
native_ choice_ dead_ end - Run the lint over one native file’s already-lowered
HirFile. Only meaningful for HIR the native frontend produced — never call this against ink-produced HIR (see the module doc’s “Native-only” section). - check_
protocol_ impls - Validate registered protocol impls: shape against the protocol’s
signature (
E115) and inferred effect row against the protocol’s contract (E114). Returns all diagnostics; an impl that fails a shape check is not row-checked (theE102-before-E103posture — don’t stack a second diagnostic on an impl that can’t even be resolved). - check_
reserved_ names - Check one file for author declarations of the reserved protocol method
names (
E113, hard error). Brink-dialect-only — the caller (per_file_diagnostics) gates the call, mirroring the annotation- content precedent: understrict-inkthere is no protocol registry and vanilla ink identifiers stay untouched. - coalesce
- The
or-coalescing TYPING rule (NS-A1;docs/stdlib-phase-c-findings.mdF19’s recommendation, implemented as ruled by wave A1’s scope): - coalesce_
lir_ lookup - Translate a
CoalesceTableintobrink-ir’s own lowering-facing mirror — the one translation point between the two crates (issue #1471), exactly ascrate::ufcs_lir_lookupis for the UFCS table. - coalesce_
types - The B1
or-coalescing typing side table for a project (issue #1492): thechain root → per-step operand/result typeschannel LIR lowering reads to choose a chain’s code shape — “inner staysOption” vs “unwrap at the end” — instead of re-deriving the answer from syntax it cannot see through (a call’s return type, aVAR’s declared type). - collect_
external_ sigs - Declaration-derived
EXTERNALsignatures (issue #786, docs/t1d-spec.md §3: “a binding declared to takeHandle<AudioInstance>rejects aHandle<Timer>argument at compile time” undertypes = strict; issue #805 widens this to the manifest’s full scalar-semantic-type vocabulary and to inline-doc-only bindings). - comparator_
callees - Every
DefinitionIdnamed as a statically-named-function callback (#fn(target)literal, or the native bare-name spelling) of a pure-callback verb call inhir, resolved throughresolutionsandindex. The salsa path (brink-db‘scomparator_contract_diagnostics_query) uses this to fetch exactly those defs’ memoized per-def effect rows — the incremental analogue of the monolithic path handingcheckthe whole-projecteffects_projecttable (theawait_condition_calleesshape). - comparator_
contract_ diagnostics - Check every pure-callback verb call in
hir(see [callback_arg_index]) whose callback is a statically-named function — an inline#fn(target)literal (ink/brink), or the sigil-free native bare-name spelling (.brink, issue #1862/#1887:map(items, double)) — against the whole-project effect rows. Returns anE119for each callback whose row provably exceeds pure·silent. - conventions_
confinement_ diagnostics - Run the confinement/unconfigured
E169checks (conventions_module_diagnostics/conventions_unconfigured_diagnostics) for a caller with no liveProjectDbto ask per-file — the off-db analysis road (issue #2335:IdeSnapshot::analyze/session.analysis(), reached through [crate::analyze_with_modules], this function’s one caller). - conventions_
module_ diagnostics - Diagnose every claiming handler declared in
hirwhen this file is not the project’s configured conventions module. - conventions_
pointer_ unresolvable_ diagnostics - Diagnose every claiming handler declared in
hirwhen the project’s[project] conventionspointer is well-formed (path-shaped) but resolves to no real file in the project (issue #2320) — a typo’d, moved, or deleted target, or a pointer whose minted module does not match any file’s real module because thebrink.tomldeclaring it was discovered at a nested key (the issue’s ownbrink-webcase). The message blames the mismatch, not the author: either side of it may be the one that’s wrong. - conventions_
unconfigured_ diagnostics - Diagnose every claiming handler declared in
hirwhen the project has no conventions module configured at all (issue #2289, part 2 of the 2026-08-05 ruling — see this module’s own doc, “What IS now enforced”). - declared_
shapes - Every declared
STRUCTshape in the project — a referrer-scoped lookup table (issue #2241). - def_
body - Find one inferable def’s own params + body from a declaring-file-scoped
HIR slice alone (FG-2.1, issue #638, Ruling 2b — backs
brink-db’s per-defdef_body_query(def)projection, theinference_index_queryprecedent applied to bodies). A thin filter over the same [collect_defs] walkcall_edges/solve_sccalready used project-wide, scoped here to exactlydef’s declaring file so the salsa wrapper records a read-edge on only that file’slowered_query— not every project file’s. Returns owned data (Vec<Param>/BlockbothClone) since the salsa caller stores the result in a long-lived memo, past the borrow of any onelowered_querycall. - def_
effect_ atoms - T2-1 (docs/effects-spec.md §2/§4, issue #860 —
def_effect_atoms(def)). One def’s raw effect atoms: the read set (VAR/CONST globals read), the write set (assignment targets resolving to a VAR/CONST), the call-kind set (EXTERNALnames directly called), the inferable direct-call edges the effect fixpoint follows, the fn-value creation targets (Fork A, issue #1726 —EffectAtoms::creates_fn_values), and whether the body calls through a function value it cannot trace (→ pessimal). Harvested by the exact same body walkreferenced_globals/call_edgesdrive — the read set here is FG-2.1’sreferenced_globals, and the direct-call edges arecall_edges’s set — so no new walk shape is introduced, only the per-def atom bundle T2 needs assembled from one pass. - effect_
atom_ name - The author-facing name of one effect-row atom.
- effective_
severity - The severity a diagnostic code should actually be reported at, given the
project’s
typespolicy and resolved[lints]policy — the single seam every diagnostic-partitioning site must call instead of the rawbrink_ir::DiagnosticCode::severitydefault. - effects_
assertion_ defs - Every def carrying a
#@effects(…)assertion inhir, paired with theDefinitionIdthe exceedance check needs its row for — the seam a salsa caller uses to fetch exactly those rows (and no others) via the per-defeffects(def)query, keeping unannotated projects inference-free. - effects_
assertion_ diagnostics - Check every knot/stitch’s
#@effects(…)assertion inhiragainstrows— that def’s inferredEffectRow, however the caller computed it: the whole-project purecrate::effects_projectfor the analyzer’s monolithic path, or, for the salsa-memoized production path, a small map built from individual per-defeffects(def)queries (only for the defs that actually carry an assertion, preserving the advisory/lazy invariant — an unannotated project never triggers effect inference at all). - effects_
project - T2-1 (docs/effects-spec.md §4, issue #860 — the whole-project effect row
table). Mirrors
infer_project’s shape for effects: harvest every inferable def’s atoms, build the same call graph off the direct-call edges, solve every SCC batch in condensation order withsolve_scc_effects(accumulating each finalized batch’s rows asknown_rowsfor its successors). A pure function of already-computed inputs — the direct-call pure-function callers and the property tests use it;brink-db’s per-SCCeffects_scc_queryreproduces the same fold incrementally. - erase_
fn_ rows - Rewrite every
Ty::Fnanywhere insidetyto carry the topFnRow— the canonical form used to compare two types modulo their effect rows. Recurses through every structural variant so a row nested insidearray<fn(): int>orfn(fn(): int): intis erased too. - external_
meta_ diagnostics - The index-driven half of the external-check family (issue #750 / FG-3
completion): host-manifest enrichment + checks for
EXTERNALs ([external_check::analyze_externals] — arityE039, unknown semantic typesE040) followed by knot/stitch doc enrichment ([external_check::enrich_callables], sameE040vocabulary), in exactly that order for both the diagnostics and thesymbol_metamerge. Reads the index and the merged inline docs only — never any file’s HIR — which is what letsbrink-dbmemoize it separately from the per-file HIR walks (file_value_meta/file_call_site_diagnostics). - file_
call_ site_ diagnostics - One file’s external call-site literal checks (
E041type mismatch,E042closed domain) — the per-file slice of [external_check::check_call_sites] (issue #750 / FG-3 completion). The checker only ever reads the file it is visiting plus the name-keyed external metas, so the per-file split is behavior-neutral; the caller owns both theExternalCheckSeveritygate and the file-order concatenation the single whole-project walk produced. - file_
value_ meta - One file’s VAR/CONST/LIST initializer/doc enrichment (issue #750 / FG-3
completion — the per-file slice of [
external_check::infer_value_meta], whichwhole_project_diagnosticsused to run as one loop over every file’s HIR). Purely presentational — never produces diagnostics. A declaration’s initializer lives in exactly one file, so the per-file split is behavior-neutral: the whole-project result is the file-order merge of the per-file maps (later files overwrite on the — deliberately deterministic — duplicate-name id collision, exactly as the single loop did). Reads no symbol ranges fromindex(onlyby_name+kind), so a range-zeroed index projection serves it. - finish_
analysis - Assemble the final
AnalysisResultfrom the already-computed layer-2 pieces (index + per-file resolutions), running the remaining passes: per-file diagnostic contributors (per_file_diagnostics) for every file, then the whole-project contributors (whole_project_diagnostics). - harvest
- Build the project-wide harvest index from every file’s HIR, upgrading any markup span kind the host manifest declares.
- hir_
has_ await - Cheap structural scan: does any knot/stitch body in
hircontain anawaitsuspension point? The laziness gate for the whole-project purity pass — an await-free project never triggers effect inference for this pass, mirroring the#@effectsexceedance pass’s own laziness gate. - hir_
has_ comparator_ site - Cheap structural scan: does any knot/stitch body in
hircontain a pure-callback verb call whose callback is an inline#fn(…)literal, or (native files only) a bare-name reference that might be one? The laziness gate for the whole-project pass — a project without such a site never triggers effect inference here, mirroring the#@effectsandawait-purity gates. - infer_
project - Infer types for every knot/stitch body across the whole project.
- inferable_
defs - Every inferable (knot/stitch) definition’s id in the project (FG-2, issue
#631). A cheap structural scan — needs the whole project’s HIR to
enumerate every def’s body. Superseded, for
brink-db’s per-def/per-SCC query wiring, byinferable_defs_from_index(FG-2.1, issue #638, Ruling 2b — the same id set, sourced from the index alone, no HIR read); kept for direct pure-function callers (e.g.infer_project) and as the equivalence anchorinferable_defs_from_index_matches_hir_derived_setpins. - inferable_
defs_ from_ index - The same inferable (knot/stitch) def id set as
inferable_defs, read directly off the index’sSymbolKind— no HIR (FG-2.1, issue #638, Ruling 2b: “inferablecomes from an index-sourcedinferable_defs_query(dep =inference_index_query, not HIR)”). A knot/stitch symbol is always indexed at exactly the same moment itshir.knotsentry is lowered (lower_single_knot/lower_top_level), so filteringindex.symbolsby kind here is output-identical to walking every file’s HIR the wayinferable_defsdoes — pinned byinferable_defs_from_index_matches_hir_derived_set. - is_
path_ shaped_ conventions_ pointer - Whether a
[project] conventionspointer names a project-relative path to a.brinkconventions module, as opposed to a bare built-in preset name (docs/prose-dialect-spec.md §3.4’s “either shape” pointer mechanism). A path either contains a directory separator or ends in the.brinkextension; a bare word (no separator, no extension) is a preset name. - is_
reserved_ protocol_ name - Whether
nameis a reserved protocol method name (F6, ruled 2026-07-19):display,compare, ornext. - iterate_
element_ ty - The element type
forbinds when iteratingiterable— the checker side of the closed builtin iterable set, unified under the registry (stdlib-spec §9.6: “foris the only v1 consumer”). Arrays iterate values; maps iterate keys in insertion order (docs/t1b-surface-spec.md §2). Everything else is not iterable v1 —None(the caller falls back toUnknown; the runtime faultsNotIndexable, conservatively carried in thefaultsrow dimension). - iterate_
val_ ty - The value type bound by
for k, v in m’s second binding (B2, issue #1461, docs/stdlib-spec.md §5/§9’s F10 ruling — two-binding map iteration is the pair storyentries()never got). Only maps have a “value at key”; arrays and ranges iterate a single element with no paired value, so they’re not represented here at all — a caller (infer::body’sBlockStmt::Forarm) falls back toTy::Unknownfor anything this returnsNonefor, the same permissive-at-compile postureiterate_element_ty’s own callers already rely on. - local_
signature - The per-file locals path
signatureitself cannot take (issue #530). - module_
diagnostics - The M-2 module import + visibility checks (docs/modules-spec.md
§2/§4/§7): import well-formedness and cross-module
#@privatereference enforcement. Purely additive — every trigger needs anIMPORT/#@private/#@publicconstruct absent from the pre-modules world, so the oracle/tier1 corpus is untouched. Genuinely whole-project (reads every file’s HIR plus the project-wide resolutions to walk cross-module references), so it stays a whole-project pass inbrink-db’s decomposedwhole_project_diagnostics_queryrather than gaining a per-file split here (issue #750 / FG-3 completion rebase note; a per-file slice is possible FG-4-era work if module churn is ever hot). - native_
strict_ only_ error - The B0.9 native strict-only enforcement point (
docs/b0-sequencing.md§B0.9’s “the strict-only ruling’s enforcement point”, issue #1342; decision-log 2026-07-19 “Typing posture ruled”: “the native surface is strict-only —types = strictis a property of the dialect, not a project knob; gradual typing does not exist on the native surface”). - no_
world_ reads_ diagnostics - Diagnose every
@[convention]handler declared inhirwhose transitive call closure reaches a world-reading (Query) or unclassified (Plain)EXTERNAL. - per_
file_ diagnostics - Per-file diagnostic contributors (issue #632 / FG-3,
docs/fine-grained-salsa-proposal.md§1 item 4): structural validation, the dialect gate, and (brink dialect only) annotation-content checks — the three passesfinish_analysisused to run as whole-project loops (validate::validate/dialect_gate::check/annotations::check, each internally iterating every file) even though none of them actually reads another file’s state: - project_
has_ coalesce - Cheap structural scan: does any expression in
hircoalesce? The laziness gate for [resolve]’s caller — a project with noor-coalescing anywhere (every ink-dialect project, by construction:InfixOp::Coalesceis native-lowering-only) never triggers whole-project inference on this pass’s account, mirroringcrate::project_has_ufcs_call’s own shape. - project_
has_ ufcs_ call - Cheap structural scan: does any call in
hirhave a multi-segment callee path? The laziness gate forresolve’s caller — a project (every ink project, by construction; see the module doc) with no dotted-callee call never triggers whole-project inference on this pass’s account, mirroringwhole_project_diagnostics’ ownneeds_effectsgate. - project_
inline_ docs - Collect inline
///docs across all files, keyed by(kind, declared name)— the project-wide doc merge feeding the external/callable/value enrichment passes. Exposed as its own seam (issue #750 / FG-3 completion) sobrink-dbcan memoize it behind anEq-cutoff query:DocBlockcarries no ranges, so any edit that leaves every///block’s parsed content intact backdates the memo even though the pass reads every file’s manifest. - ref_
assignable - Is a value of type
sourcelegal as the argument bound to arefparameter declaredtarget? - referenced_
globals - Pass 1b, exposed per one definition (FG-2.1, issue #638, Ruling 1 —
referenced_globals(def), the same per-def body-facts family ascall_edges). The VAR/CONST global idsdef’s body references, recorded by [body::BodyResult::referenced_globals] regardless of whether a real globals map was supplied — this call passes an empty one, exactlycall_edges’s “discard the computed types, keep the structural fact” shape.brink-dbresolves each returned id viasignature_queryand hands the walk a small narrowBTreeMapbefore the real solve runs (two walks: this scan, thensolve_scc— see the spec’s Ruling 1 tradeoff note). Also the per-def global read set a future T2 effect row needs — named and shaped for that reuse now, no speculative machinery added. - resolve
- Resolve one file’s references against the project-wide symbol index.
- resolve_
annotation - Resolve a parsed type annotation into the checker’s
Tyuniverse. - resolve_
type_ policy - THE
types-default resolution function (issue #1127, decision-log 2026-07-19 “Typing posture ruled”). An explicittypes = …— a CLI--typesflag, abrink.toml[project] typeskey, an editor/LSP API call — always wins. When the project never says, the default is keyed on the dialect: - resolve_
ufcs_ calls - Resolve every UFCS-shaped call in the project, returning the verdict side table plus the diagnostics the four outcomes above produce.
- scc_
graph - Partition
graphinto SCCs and compute the condensation DAG in one pass (FG-2, issue #631). [topo_order] is now a thin projection of this (.order) kept for its own existing tests/callers;scc_membership_queryis the new consumer that needs the adjacency too. - signature
- Compute the signature stub for one definition.
- solve_
scc - Solve exactly one SCC batch (FG-2, issue #631 —
solve_scc(SccId)). - solve_
scc_ effects - Solve one SCC batch’s effect-row fixpoint (spec §4 — the same per-SCC join
TM-1’s type solver runs, lifted to the effect lattice). Lifts
infer::solve_one_batch’s shape:known_rowsmust already carry the finalized row of every def outsidebatchthat a member calls (every condensation-predecessor SCC’s rows);atomscarries every batch member’s harvestedEffectAtoms. - strict_
diagnostics - The strict typed-mode pass (docs/typed-mode-spec.md §1/§9-step-3),
extracted from
whole_project_diagnostics’s body (issue #750 / FG-3 completion) sobrink-dbcan run it without also paying for the external-check family’s inputs. Returns empty undertypes = gradual— byte-identical, forever. - symbol_
index - Build the project-wide declaration index from per-file symbol manifests.
- symbol_
index_ with_ modules - The merged symbol index with
DefinitionIds qualified by each file’s declared module (M-1, docs/modules-spec.md §5). - ufcs_
lir_ lookup - Translate a
UfcsTableintobrink-ir’s own lowering-facing mirror (brink_ir::lir::UfcsLookup/UfcsVerdict) — issue #1506’s one conversion point, so theUfcsVerdict→brink_ir::lir::UfcsVerdictmapping lives in exactly one place rather than once per caller.brink-irsits below this crate in the crate graph (this crate depends onbrink-ir, never the reverse), so it cannot provide this itself — seebrink_ir::lir::UfcsVerdict’s own doc. Every LIR-lowering caller shares this:brink-db’sufcs_resolution_query(the production path) andassemble_analyzer_tables— the salsa-free path used bybrink-test-harness(corpus::compile_and_explore_from_brink_native) and any other caller with no salsa layer of its own to memoize the table in. - ufcs_
resolution - The B3a UFCS verdict side table for a project (issue #1482, D2): the
node → resolved targetchannel LIR lowering reads to choose between emitting a call through a field’s value and emitting the desugared free callname(recv, args), and that IDE hover/go-to-def reads to name the real target of a method-call-shaped site. - unify
- Unify (join) two observed types for the same slot.
- unify_
all - Fold
unifyover an iterator of observed types, starting fromTy::Unknown(the identity). Used for collection-literal element joins (spec §5:#[1, 2.0]isArray<float>) and for folding multiple observations of the same local/return slot across a body. - validate_
admission - Run every §4.2 admission check over one file’s already-lowered
(HirFile, SymbolManifest)pair. - validate_
native_ accept_ list - Run the B0.9 accept-list over one native file’s already-lowered
HirFile. Non-suppressible, mirroringcrate::validate_admission— callers must not route the result throughapply_suppressions. Only meaningful for HIR the native frontend produced; never call this against ink-produced HIR (see the module doc). - whole_
project_ diagnostics - Whole-project diagnostic contributors that genuinely need cross-file
state (issue #632 / FG-3 design doc §1), now composed of the same
per-pass seams
brink-db’s decomposed queries wrap (issue #750 / FG-3 completion) —module_diagnostics,strict_diagnostics,external_meta_diagnostics, per-filefile_value_meta, and per-filefile_call_site_diagnosticsbehindcall_site_metas— in exactly the pre-split order, so the query-composed result is identical to this monolithic one by construction (pinned byquery_equivalence.rs).
Type Aliases§
- Coalesce
Table - Every
or-coalescing chain’s recorded typing, keyed at the chain root (see the module doc for why not per step). - Module
Map - Map from file to its resolved module. Absent entries (and undeclared modules) hash by bare name — byte-identical to the pre-modules scheme.
- Resolution
Map - Maps reference use-sites to their resolved definitions, with file provenance.
- Ufcs
Table - Every UFCS call site’s verdict for one project.