Skip to main content

Crate bynk_ir

Crate bynk_ir 

Source
Expand description

P6.1 (design/tracks/the-ir.md §6, #1141): the IR’s core node types — IrExpr/IrExprKind/IrStmt, Part 6.2 of design/bynk-greenfield-compiler.md.

R6.1 — “Every IrExpr carries its type. The constructor requires it; there is no side table and no fallible lookup from the emitter to the checker.” This module is the type only; bynk_lower is the &CheckedProgram → Ir pass that constructs values of it.

Identity fields are adapted, not literal (Decision B, extending P6.0’s own precedent, ADR 0333 the-ir-callee-in-bynk-check): the reference’s DefId/FieldId/LocalId/VariantId arena does not exist in this codebase (no Resolve phase mints them — project-model.md §3.4 deferred that to phase 8), so every such slot becomes whatever cheap resolved handle the checker already has — Arc<TypeDecl>/Arc<FnDecl> for a declaration, String for a name with no arena of its own. Call’s payload is Callee verbatim — P6.0 already did this exact substitution for call-dispatch identity, so Call needs no adaptation of its own here.

The whole Part 6.2 shape lands in one piece (Decision D): every variant below exists, including Match/Variant/Call/Lambda, so a later slice (P6.2, P6.4, P6.5) widens only bynk_lower’s match, never this type. Match’s own payload is four types: IrPat/IrArm/ Exhaustive are P6.4’s own commission (#1157, Part 5.1/5.2 of the reference); MatchForm is P6.5’s own (#1159, R5.2/R5.3, scoped to shape only — Decision A). All four are real, constructible types as of P6.5, wired into a real IrExprKind::Match by bynk_lower’s ExprKind::Match arm, which calls P6.4’s own standalone constructors (bynk_lower::lower_pattern_ir/bynk_lower::lower_arm_ir/ bynk_lower::lower_exhaustive_ir) verbatim. Question/Is stay desugars-to-Match in name only — neither gets real construction this slice, each for a reason specific to it (see bynk_lower’s own todo!() text for each).

Decision D’s own “never widens beyond the reference’s Part 6.2 shape” is not absolute — it held only as long as the reference’s own node set was complete (IrExprKind::BinOp/IrExprKind::Neg/ IrExprKind::InterpStr, #1189). design/bynk-greenfield-compiler.md §6.2’s own listing (Const, Local, Global, Record, Variant, Field, List, Block, If, Match, And, Or, Not, Return, Call, Lambda, Await, Send, Pure) never names comparison, arithmetic, unary negation, or string interpolation at all — confirmed a true omission, not a deliberately-out-of-scope row this track chose to defer (unlike, say, Question/Is above, each of which the reference does name and this slice explicitly declines). P6.2 (#1143) and P6.3 (#1145) each independently confirmed the gap and left it a todo!() rather than force-fitting it under Decision D‘s closed-shape framing; #1189 settled it as buildable, three new variants, added here rather than deferred indefinitely — real programs use +/-/</== routinely (a certified .bynk invariant like balance >= 0 is ordinary, not an edge case), and the checker already resolves every one of these expressions’ types (bynk-check/src/checker/expressions.rs’s check_binop/ check_unary, and checker.rs’s own InterpStr hole-checking) — nothing about them was actually blocked on new checker work, only on this type gaining a place to land them.

P6.6 (#1161) adds IrItem/TypeShape (Part 6.6) — a separate top-level type from IrExpr, not a new IrExprKind variant: declarations and expressions are different node families in the reference sketch, and unlike Match’s own payload, IrItem carries no constraint that its whole seven-variant design-sketch shape must exist as of this slice — see IrItem’s own doc comment for exactly which are real.

P6.7 (#1163) adds StoreFieldIr/StoreKindIr/IndexIr (Part 6.6’s own trailing two structs, R6.14) — an agent store field’s own state shape and index-table keys, derived once here rather than re-derived independently by both the checker’s own ephemeral checker::StoreField dispatch and the shipped emitter’s own store_map_fields/store_cache_fields/store_log_fields/… (bynk-emit/src/emitter/emit.rs). Same posture as every prior P6.x slice: no IrItem variant references these yet — IrItem::Agent/ Service remain unconstructed (see IrItem’s own doc comment for exactly what still blocks them).

P6.8 (#1165) adds CommitShape/IrPredicate (Part 6.7’s own trailing two types, R6.15) — a handler body’s own resolved one-of-three commit shape, decided once here from a mutating Callee::Store write or a bare :=, rather than re-derived at emission time by the shipped emitter’s own name-matching block_writes_state (R6.5). Same posture again: no IrItem variant references either yet — IrHandler itself still does not exist, and no rule in design/tracks/the-ir.md’s own slice table commissions it (see IrItem’s own doc comment).

P6.9 (#1167) adds IrStmt::Assign/ActorBinder/IrHandler (Part 6.7’s own trailing construct, R6.16) — a real, standalone, constructible agent on call handler, plus the Statement::Assign prerequisite gap (todo!() since P6.1, twice deferred by P6.7/P6.8’s own Risks) it needed closed first: bynk_lower::lower_handler_ir cannot lower a store-writing handler body without a real IrStmt target for :=. binder: Option<ActorBinder> is always None from bynk_lower::lower_handler_ir this slice — an agent handler structurally cannot carry one (bynk.actor.by_on_agent); a real service handler’s own non-None binder needs a bynk-check change this slice does not make (see IrHandler’s own doc comment). Same posture again: no IrItem variant references IrHandler yet — IrItem::Agent/Service remain unconstructed (see IrItem’s own doc comment).

P6.10 (#1169) adds IrItem::Agent — the assembly P6.9’s own Risks section named without numbering it: every ingredient (StoreFieldIr since P6.7, CommitShape/IrPredicate since P6.8, IrHandler since P6.9) was already real, but nothing combined them into one IrItem value, and IrItem had no variant to carry the result. This is the first IrItem variant with a real consumer shape below the top level — bynk_lower::lower_agent_item_ir calls every prior slice’s own standalone constructor rather than re-deriving any of their logic, the same “wire, don’t re-derive” posture this whole module has held since P6.0. IrItem::Service/Actor/Capability/Provider remain deferred, each for its own reason (see IrItem’s own doc comment).

P6.11 (#1171) adds IrItem::Service — the sibling assembly to P6.10’s Agent, closing both blockers IrItem’s own doc comment named: #1170 made a service handler’s binder readable post-certify for the first time, and this slice specifies the two types the reference names but never defines for a service (ProtocolIr, PolicyIr). bynk_lower::lower_service_handler_ir is a new sibling of bynk_lower::lower_handler_ir, not a widening of it — the two seed disjoint scopes, and widening would have deleted the agent-only by assertion that today catches a service handler reaching the wrong entry point. A from websocket lifecycle handler’s own body (on open/on message/on close) is the one named exception: the checker-injected synthetic connection param has no IR target yet, so lowering one hits an explicit todo!() rather than a silently wrong tree — see bynk_lower::lower_service_handler_ir’s own doc comment. IrItem::Actor/Capability/Provider remain deferred, each with its own already-tracked, genuinely unsettled blocker (see IrItem’s own doc comment).

P6.12 (#1173) adds IrItem::Capability — the reference’s own ops: Vec<OpSig> sketch (bynk-greenfield-compiler.md:1134) named a type it never defined anywhere in the document; OpSig is that missing shape, adapted from bynk_syntax::ast::CapabilityOp under this module’s own “no arena” substitution (Vec<(String, TyId)> for params, mirroring IrItem::Fn::params exactly). bynk_lower::lower_capability_item_ir resolves each op’s own params/ return_type in that op’s own rigid-variable scope (op.type_params) — a capability op’s type parameters are scoped to the op itself, not the capability, unlike a method’s generic receiver — the same per-op treatment the checker’s own CapabilityOpInfo already gives a generic op (context_checks.rs’s build_capability_op_info). IrItem::Actor/ Provider remain deferred, each with its own already-tracked, genuinely unsettled blocker (see IrItem’s own doc comment).

P6.14 (#1174) adds IrItem::Provider — #1174’s own grounding pass found this buildable, unlike its sibling Actor: the reference’s own body: ProviderBody // Bynk ops | External(module) comment names a type it never defines, the same gap OpSig closed for Capability, and ProviderDecl::external already carries the exact dispatch it needs. bynk_lower::lower_provider_op_ir is a new sibling of bynk_lower::lower_fn_body_ir, not a widening of it, for the same “each body-lowering entry point seeds its own scope” reason bynk_lower::lower_handler_body_ir’s own doc comment already gives: no self, no store cells, just a provider op’s own params — given capability calls need no scope entry of their own, the same already-generic Callee-wrapping bynk_lower::lower_handler_body_ir’s own doc comment credits for handler bodies. IrItem::Actor remains deferred, its own already-tracked blocker unchanged by this slice (see IrItem’s own doc comment).

Structs§

ActorBinder
P6.9’s real ActorBinder ([DECISION A], #1167) — referenced by the reference’s own IrHandler sketch (bynk-greenfield-compiler.md:1169-1177, binder: Option<ActorBinder>) but never defined anywhere in the document — the same “referenced, not specified” gap #1161’s own Decision C named for EmbedIr, #1163’s own Decision C named for IndexIr, and #1165’s own Decision A named for IrPredicate. Mirrors the checker’s own already-resolved actor_binding: Option<(String, TyId)> shape (bynk-check/src/checker.rs’s HandlerBodyCheck::actor_binding): binder is the bound name, ty the sealed Ty::Actor(identity) or Ty::ActorSum(members) — both ordinary, already-real TyIds, no synthetic type needed the way <Agent>State was for P6.8’s state_ty. No dedicated lower_actor_binder_ir constructor: the pair has no further structure to derive, mirroring EmbedIr’s/IndexIr’s own “no further structure, plain tuple/alias” precedent — as of P6.11 (#1171), bynk_lower::lower_service_handler_ir is the real caller that reads TypedCommons::actor_bindings (#1170) and writes ActorBinder { binder, ty } directly; bynk_lower::lower_handler_ir (agent-only) still never does — see IrHandler’s own doc comment.
CacheIr
#1228’s own CacheIr — a GET handler’s own @cache(maxAge:, scope:) freshness policy, interpreted the same “raw {name, value: Expr} pairs mean nothing on their own” discipline PolicyIr’s own doc comment argues for, but deliberately not a PolicyIr field. PolicyIr itself is built only by bynk_lower::lower_policy_ir, which only bynk_lower::lower_service_item_ir calls — and nothing in the shipped emitter constructs a real IrItem::Service yet (every call site is this module’s own test suite). Nesting CacheIr under PolicyIr would land it inert: real in bynk_lower’s own tests, with zero effect on any emitted route. @cache is also handler-scoped, not service-scoped (PolicyIr’s whole shape), so it was never a natural fit regardless. bynk_lower::lower_route_cache_ir is a standalone reader instead, wired directly into emitter/workers_entry.rs’s own route construction — the same live, standalone-consumer shape lower_protocol_ir/ lower_handler_given_ir/lower_actor_seam_ir already established.
CapRefIr
P6.14’s real CapRefIr ([DECISION A], #1174, review of #1186) — one bynk_syntax::ast::CapRef entry of a provider’s own given clause, under this module’s usual “no arena, bare name” substitution: context: Option<QualifiedName> flattens to Option<String> via QualifiedName::joined() (the same .-joined form resolve_consume_prefixbynk-emit/src/project.rs — already resolves against consumes/aliases), and name: Ident flattens to String, mirroring every other bare-name identity field in this module. Deliberately not resolved further here: which context a Some prefix actually names is whole-project consumes/alias data, the same phase boundary IrItem’s own doc comment already names for ProviderBody::External’s missing module field — this type only preserves what CapRef itself carries, unresolved.
ConnectionBinder
P6.13’s real ConnectionBinder ([DECISION G], #1179) — the synthetic leading connection: Connection[out] binding a from websocket lifecycle handler’s body receives, bynk_lower::lower_service_handler_ir’s own return value for exactly the on open/on message/on close handlers of a ServiceProtocol::WebSocket service. Mirrors the checker’s own open_connection_param (bynk-check/src/context_checks.rs:2020-2032): ty is the resolved Ty::Connection(out_ty), always present regardless of handler kind — unlike ActorBinder, there is no None case here, since a websocket lifecycle handler is checker-guaranteed to receive this binding (bynk.service.websocket_open_arity, context_checks.rs:742-763, plus the unconditional injection at context_checks.rs:1944-1954).
CorsIr
The payload of PolicyIr::cors — present only when the source declares a cors { } block at all (ADR 0159’s own opt-in posture); the asymmetry with PolicyIr::security is this struct’s load-bearing content, not an inconsistency.
EventPatternIr
The payload of ProtocolIr::Events’s own pattern — a from Events(E { field: value, .. }) structural filter, [DECISION C] (#1171). Not bynk_syntax::ast::EventPattern reused verbatim, unlike SchemaVersionPattern: that type carries rest_span (a parse artefact for the grammar-required trailing .., giving a later reader nothing to act on) and its own EventPatternValue::Variant is an unresolved, optionally-qualified name pair — exactly the shape this module’s whole posture rejects everywhere else.
EventSubscriberShape
#1226/#1187 slice 6: the two facts a service’s own event-subscriber shape needs, captured at that unit’s own check time (its CheckedProgram does not survive past check_unit_files’s per-file loop) so a different unit’s own composition root can later decide whether its subscriber to this service wants the event envelope forwarded, without re-walking this unit’s raw UnitTable. Pure syntax, zero TyId dependency. Produced by bynk_lower::lower_event_subscriber_shapes_ir, sized like #1187’s own unit_callees (#1202) accumulator.
FnSig
P6.18: a fn‘s own resolved signature, with no body and no receiver — the narrow, OpSig-shaped sibling a foreign unit’s attached method needs when only its signature will ever be rendered (emit_attached_ methods’ delegating forward at bynk_emit::emitter::emit::emit_forwarded_methods), never its body. Deliberately not IrItem::Fn: that variant mandates lowering body: IrExpr through bynk_lower::lower_fn_body_ir, which still todo!()s on ExprKind::Question/Is (design/tracks/ the-ir.md §6’s own P6.3 correction) — forcing every uses-imported method through that gate for a signature nothing here ever reads would make this reader strictly less total than the raw-TypeRef code it replaces, for zero benefit. bynk_lower::lower_fn_sig_ir_from_types resolves params/return_ty in the scope the method’s own [T, …] list names (mirroring bynk_lower::lower_op_sig_ir_from_commons‘s identical type_params treatment) — a genuinely unresolvable name degrades to Ty::Unit, deliberately, the same non-panicking posture OpSig already established: nothing checker-side actually validates an attached method’s own params/return_type against the importing context’s own visible types (only the declaring commons’ own checking does), so a resolve miss here is an expected, not exceptional, state.
GlobalRef
The payload of IrExprKind::Global — adapted per Decision C’s narrow scope, refined during implementation: a bare nullary sum-variant constructor reference (Miss, PaymentDeclined), identified structurally (exactly one sum type in TypedCommons::types owns a variant of this name with an empty payload — the same “unique owner” test check_ident’s own unconditional fallback arm uses, bynk-check/src/checker/expressions.rs:103-130).
IrArm
P6.4’s real IrArm (Part 5.1, #1157) — the reference’s own bare sketch (struct IrArm { pat, guard, body, binds }) adapted per this module’s “no arena” substitution (local: LocalId -> String, pat: PatId -> IrPat owned directly) plus one field the sketch doesn’t carry: binding_mode (Decision C, R5.5, computed once during this arm’s own construction rather than re-walked by any later reader — design/bynk-greenfield-compiler.md:749-751). See BindingMode’s own doc comment for exactly what this one arm-level flag does and doesn’t tell a future reader.
IrExpr
A lowered expression: its shape, its checked type, and the source span it came from. ty is required at construction (R6.1) — never Option, never looked up lazily by a reader.
IrHandler
IrPredicate
P6.8’s real IrPredicate ([DECISION A], #1165) — referenced by the reference’s own CommitShape::Transactional { invariants: Vec<IrPredicate>, transitions: Vec<IrPredicate> } and IrItem::Agent’s own sketch (bynk-greenfield-compiler.md:1130-1131/1182), but never defined anywhere in the document — the same “referenced, not specified” gap #1161’s own Decision C named for EmbedIr and #1163’s own Decision C named for IndexIr. One type serves both an agent’s own invariants and transitions fields, rather than two near-identical structs: Invariant/Transition (bynk_syntax::ast) already share this exact shape — a name plus a Bool-typed predicate expression — and bynk_lower::lower_invariant_ir/bynk_lower::lower_transition_ir differ only in how they seed the predicate’s own scope (an invariant over the agent’s store Cell fields, a transition over old/new), not in what they produce. name: String is this module’s own “no arena” substitution ([DECISION B] extended) — a predicate has no DefId of its own in the reference either, referenced only by position within its owning Vec.
OpSig
P6.12’s real OpSig ([DECISION A], #1173) — referenced by the reference’s own IrItem::Capability sketch (bynk-greenfield-compiler.md:1134, ops: Vec<OpSig>) but never defined anywhere in the document — the same “referenced, not specified” gap #1161’s own Decision C named for EmbedIr, #1163’s own Decision C named for IndexIr, #1165’s own Decision A named for IrPredicate, and #1167’s own Decision A named for ActorBinder. Adapted from bynk_syntax::ast::CapabilityOp — a signature only, no body — under this module’s already-established “no arena” substitutions: params: Vec<(String, TyId)> mirrors IrItem::Fn::params exactly (Decision E, #1161), and type_params: Vec<String> mirrors the checker’s own already-resolved CapabilityOpInfo::type_params (bynk-check/src/checker.rs) — a bare rigid-variable name, not a TypeParam AST node, since nothing here re-derives bounds a capability op’s own [T, …] list never carries in the first place (#926). bynk_lower::lower_op_sig_ir resolves params/return_ty in the scope type_params names, mirroring context_checks::build_capability_op_info’s own vars treatment (bynk-check/src/context_checks.rs) so a generic op’s own T survives as Ty::Var("T") rather than collapsing to Ty::Unit. On a genuinely unresolvable name a params/return_ty entry is Ty::Unit, deliberately — see bynk_lower::lower_op_sig_ir’s own doc comment for why that mirrors the checker’s own fallback rather than panicking.
PolicyIr
P6.11’s real PolicyIr/CorsIr/SecurityIr ([DECISION D], #1171) — the interpreted (not passed-through) form of a from http service’s cors/security/limits blocks, bynk_lower::lower_policy_ir’s own return value. The reference names PolicyIr once, in the IrItem::Service sketch itself (:1132), and never elsewhere — the same “referenced, not specified” gap every trailing struct in this module has carried before its own slice specified it.
ProviderOpIr
P6.14’s real ProviderOpIr ([DECISION A], #1174) — one ProviderOp (bynk-syntax/src/ast.rs:604-611), signature and body, unlike OpSig’s signature-only shape: a CapabilityOp never carries a body (a capability is a contract), but a ProviderOp always does. No type_params, unlike OpSig: ProviderOp carries none of its own (#1173’s own OpSig::type_params doc comment names the same absence for CapabilityDecl, but a capability op’s [T, …] (#926) has no provider-op equivalent — nothing in the grammar or the checker’s own check_provider_decls gives a provider op a [T, …] list to parse).
SecurityIr
The payload of PolicyIr::security — always present for an HTTP service (see PolicyIr::security’s own doc comment).
StoreFieldIr
P6.7’s real store-field state shape (design/bynk-greenfield-compiler.md §6.6, R6.14, #1163) — the payload of an agent store field declaration, bynk_lower::lower_store_field_ir’s own return value. Mirrors checker::StoreField’s own five-kind dispatch (bynk-check/src/checker.rs) in shape, but is persistent IR data with no consumer yet, not that checking pass’s own ephemeral, per-agent scratch value — the two are deliberately not unified (see bynk_lower::lower_store_field_ir’s own doc comment). No IrItem variant references this yet — IrItem::Agent/Service remain unconstructed (IrItem’s own doc comment names exactly what still blocks them).

Enums§

ActorSeamIr
#1187’s slice 3: a handler’s resolved actor-verification seam, wrapping bynk-check’s own five already-resolved seam structs (bynk-check/src/actors.rs) by value — confirmed none carry any bynk_syntax::ast/TypeRef/Expr: every field is String/bool/ i64/Option/Vec (or, for BearerSeam::authorization, ClaimPredicate, itself a plain recursive String/Box enum). Built by bynk_lower::lower_actor_seam_ir, which tries the five resolvers in the one priority order that actually matters — sum_members_for first, since it’s the only resolver whose result can otherwise collide with bearer_seam_for’s (a sum’s own first peer can itself be Bearer-schemed; bearer_seam_for has no by.is_sum() guard of its own to prevent that). The other three pairs are mutually exclusive by construction — each single-actor resolver requires the primary actor’s own auth scheme to match one specific Scheme variant, a closed set — so their relative order here is a no-op, not a second load-bearing decision.
BindingMode
R5.5, Decision C — OrDispatch iff IrPat::Or occurs anywhere in the arm’s own pattern tree, computed once by bynk_lower::lower_arm_ir.
CommitShape
P6.8’s real CommitShape (Part 6.7, R6.15, #1165) — a handler body’s own resolved one-of-three commit shape, bynk_lower::lower_commit_shape_ir’s own return value. Matches the reference’s own three-variant shape verbatim (bynk-greenfield-compiler.md:1179-1183) — no substitution needed, Transactional’s own payload already reuses IrPredicate rather than carrying Invariant/Transition AST nodes directly. Shape-agnostic between an agent and a service handler ([DECISION F]): as of P6.11 (#1171), bynk_lower::lower_service_handler_ir is the real service call site this decision predicted, passing empty invariants/transitions slices, and the identical write-detection walk (bynk_lower::lower_commit_shape_ir’s own doc comment) naturally finds neither a mutating Callee::Store nor a bare := in a service body (a service declares no store fields to write), so Transactional is never constructed for one — the shipped emitter’s own emit_service already only ever produces the other two shapes, for the same reason.
ConstVal
A constant value — the payload of IrExprKind::Const. Adapted from the reference’s own ConstVal (Int Float Str Bool Unit Bytes, Part 6.2’s comment): DurationMillis replaces Bytes because Bynk has a real <int>.<unit> duration literal (ExprKind::DurationLit) Const must cover, while Bytes has no literal AST form at all in this language — every Bytes value comes from a static-constructor call (Bytes.fromUtf8/fromBase64/empty(), Callee::Intrinsic territory, not a literal).
EventPatternValueIr
One EventPatternIr field’s own matched value.
Exhaustive
P6.4’s real Exhaustive (Part 5.2, R5.6/R5.7, #1157) — Partial’s own witness payload reuses the checker’s already-shipped missing_patterns shape (Vec<String>, human-readable witness descriptions) rather than inventing the reference’s own unspecified PatternWitness struct (Decision B). Both variants are real and matchable, but this slice’s own bynk_lower::lower_exhaustive_ir only ever constructs Total — see that function’s own doc comment for why Partial is real, inhabited code, yet unreached here.
IrBinOp
IrExprKind::BinOp’s own operator tag (#1189) — every bynk_syntax::ast::BinOp member that lowers into BinOp rather than its own dedicated IrExprKind variant or a desugar (see BinOp’s own doc comment for which and why). Deliberately a plain tag with no payload of its own — lhs/rhs already carry their own resolved ty, and unlike, say, StoreKindIr, no variant here needs anything beyond its own identity.
IrExprKind
A lowered expression’s shape. Every node kind from Part 6.2 exists here (Decision D); bynk_lower implements real construction only for the subset named in design/tracks/the-ir.md’s own P6.1 row — every other arm is a named todo!() in the lowering pass, not a missing variant here.
IrHandlerKind
P6.9’s real IrHandler ([DECISION C], #1167) — an agent on call handler’s own resolved shape, bynk_lower::lower_handler_ir’s own return value. Six of the reference’s own eight sketched fields are its verbatim shape (bynk-greenfield-compiler.md:1169-1177) under this module’s already-established substitutions: kind: IrHandlerKind — originally HandlerKind reused verbatim from bynk_syntax::ast (the same “reused, not adapted” treatment IrExprKind::Call’s own Callee payload got), converted to a real IR-native mirror by P6.24a once a purely-structural emitter reader (no body, no IrItem::Service) needed to match on it without spelling bynk_syntax::ast — see IrHandlerKind’s own doc comment; params/ given are this module’s standard “no arena” substitution (params: Vec<(String, TyId)> mirrors IrItem::Fn::params exactly; given: Vec<String> reads each CapRef::key(), the same identity Callee::Capability already uses); binder: Option<ActorBinder> per ActorBinder’s own doc comment; body: IrExpr is bynk_lower::lower_handler_ir’s own new handler-body lowering entry point (parallel to, but distinct from, bynk_lower::lower_fn_body_ir — that entry point’s own doc comment names exactly why a handler body cannot reuse it); commit: CommitShape calls bynk_lower::lower_commit_shape_ir (P6.8, unchanged); effectful: bool reuses IrItem::Fn::effectful’s own derivation (Ty::Fn’s doc: effectful iff ret is Effect[_]) unchanged.
IrHttpMethod
IrHandlerKind::Http’s own method field — a field-for-field mirror of bynk_syntax::ast::HttpMethod, same reasoning as IrHandlerKind itself.
IrInterpPart
IrExprKind::InterpStr’s own per-part payload (#1189) — the IR-side mirror of bynk_syntax::ast::InterpPart, substituting Hole’s raw Box<Expr> for an already-lowered Box<IrExpr> under this module’s usual “carry the lowered form, not the source form” discipline (the same substitution every other IrExprKind payload already makes).
IrItem
P6.6’s real declaration IR (design/bynk-greenfield-compiler.md §6.6, #1161) — a top-level declaration’s own shape, the payload bynk_lower::lower_type_item_ir/bynk_lower::lower_fn_item_ir construct. Identity is adapted per this module’s own “no arena” substitution (DefId -> Arc<TypeDecl>/Arc<FnDecl>, the same substitution Record/GlobalRef already made).
IrPat
P6.4’s real Pattern IR (design/bynk-greenfield-compiler.md §5.1, #1157): a pattern’s own recursive shape, six variants mapping one-to-one onto bynk_syntax::ast::Pattern’s own six (Wildcard, Binding, Literal, Variant, Refined, Or). bynk_lower::lower_pattern_ir is the &Pattern -> IrPat constructor, tested standalone — not yet wired into IrExprKind::Match/Question/Is construction (P6.5’s own commission). No PatId arena — a pattern owns its children directly (Box<IrPat>), the same “no arena exists in this codebase” substitution this module’s own doc comment already applies throughout.
IrStmt
A lowered statement — Bynk’s real statement surface (Let/EffectLet/Expect/Send/Do/Assign) folds down onto the reference’s own two-variant IrStmt (Part 6.2), extended by P6.9 (#1167) with a third: Send/Do become Expr wrapping IrExprKind::Send/IrExprKind::Await; EffectLet becomes Let wrapping an Await. Assign (a Cell := write) is real as of P6.9 ([DECISION B], #1167) — this comment used to (twice) forward-reference Callee::Store territory for it, on a premise P6.9’s own grounding pass found false: checker.rs’s own Statement::Assign arm resolves a.target.name directly against ctx.store_fields by bare name and never keys a Callee at all (only a.value, an ordinary sub-expression, ever gets one), so no ExprId-keyed sink was ever actually needed — IrStmt::Assign is the ordinary two-field Let-shaped fix that was available the whole time. Expect (test-only) has no target here — not named by any rule this track commissions — and stays todo!() in the lowering pass, not silently dropped.
MatchForm
P6.5’s own real MatchForm (#1159, R5.2/R5.3) — scoped to shape only (Decision A). The reference’s own table crosses tail-vs-value position with flat-vs-if-chain shape into four printed forms, but position is decided by where in the AST the caller already is — the same mechanism that already decides tail-vs-value for every other IrExprKind, including If, which P6.1 already committed to modelling position-agnostically (this module’s own IrExprKind::If doc comment). Match’s own scrutinee/arms/exhaustive are identical regardless of position, so only the shape bit is recorded here — a future printer derives the tail-vs-value physical shape itself, the same way it would for If.
ProtocolIr
P6.11’s real ProtocolIr ([DECISION A], #1171) — one variant per bynk_syntax::ast::ServiceProtocol variant, bynk_lower::lower_protocol_ir’s own return value. The reference’s own sketch specifies only two of the six: Events { event, pattern, schema_dispatch } (bynk-greenfield-compiler.md:1881) and WebSocket { in_ty, out_ty } (:1959) — field names taken verbatim from those two rows. Call/ Http/Cron carry no payload, not because one was dropped: the actual per-trigger binding (a route, a schedule) lives on each handler (HandlerKind::Http { method, path }/Cron { expr }), already reachable through IrHandler::kindServiceProtocol’s own doc comment says this in as many words (“the endpoint lives on each handler”), which is why the reference never spells these three out either. E2 (:1737) constrains the set, not the shape: “a closed nominal set … grows one variant per real trigger” — the AST’s own closed ServiceProtocol already satisfies that exactly, so this type is total over what a certified program’s own service can declare, the same claim StoreKindIr’s own doc makes about Queue being gated pre-certify.
ProviderBody
P6.14’s real ProviderBody ([DECISION A], #1174) — referenced by the reference’s own IrItem::Provider sketch (bynk-greenfield-compiler.md:1135, body: ProviderBody // Bynk ops | External(module)) but never defined anywhere in the document as a real Rust type, the same “referenced, not specified” gap Capability’s own OpSig carried before #1173 settled it. Mirrors ProviderDecl::external (bynk-syntax/src/ast.rs:592-595) exactly: true (no brace block, an adapter-supplied binding) becomes External, false (a real Bynk- authored implementation) becomes Bynk. See IrItem’s own doc comment for why External carries no module field despite the reference’s own parenthetical, and why it carries given instead of omitting that too.
StoreKindIr
P6.7’s real StoreKindIr (Part 6.6, R6.14, #1163) — five variants, one per functional storage kind (Cell/Map/Set/Cache/Log). Queue is not a variant here: bynk.store.kind_unsupported gates it before certify (R3.10), so this type is total over what a certified program’s own store fields can actually contain, not a subset some later slice needs to extend. [DECISION B]: Duration substitutes to i64 milliseconds throughout — the same substitution ConstVal::DurationMillis and checker::StoreField::Cache’s own already-resolved TTL already made.
TypeShape
P6.6’s real TypeShape (Part 6.6, #1161) — a declared type’s own resolved structure, the payload of IrItem::Type. Covers the AST’s four TypeBody variants (Refined/Record/Sum/Opaque) with the reference’s own three ([DECISION A]): Opaque unifies into Refined via its own opaque: bool field, mirroring emitter/emit.rs’s own RefinedShape { base, refinement, is_opaque } — the shipped emitter’s own precedent for exactly this unification (emit_type, emitter/emit.rs:19).

Constants§

MUTATING_CELL_OPS
v0.98 (ADR 0125): <cell>.update(f) is a read-modify-write of the working state — the bare := write form is Statement::Assign, checked separately and unconditionally, no method name involved.
MUTATING_LOG_OPS
v0.95: <log>.append mutates the durable array (ADR 0121) — every other Log method is a query-lifting read.
MUTATING_MAP_CACHE_OPS
Decision C (#1165): the closed sets of mutating storage-op names, one pub constant per kind group — read by bynk_lower::body_writes_state’s own Callee::Store-keyed write-detection walk (P6.8, Decision B), which needs no receiver-name gate at all: a Callee::Store already carries the field’s own resolved identity, not a name that could be shadowed. Until #1196, this module also had its own bare-Ident-receiver-name-matching reader (block_writes_state’s own mutating_op, deleted) — a single shared source avoided the class of drift #1164’s own review caught twice for a different pair of independently hand-maintained copies (cache_ttl_millis’s DurationLit extraction, store_map_indexes’s dedup); now there is only the one reader. Live in bynk-ir (not bynk-emit or bynk-lower specifically, moved here from bynk-emit::emitter at the P7.12 crate carve, no behaviour change) since a future bynk-emit-side reader (a Service handler’s own write detection, say) may need them again, the same reasoning that kept them pub(crate) rather than bynk-lower-private before the carve. Map/Cache share one list — both support the same four entry ops — rather than two identical ones.
MUTATING_SET_OPS
v0.83: <set>.add/<set>.remove mutate a store Set[T] field.

Functions§

block_uses_emit
Events track, slice 0 (spine #936): does this block contain a real Events.emit[...] call anywhere — including nested branches, match arms, lambdas, and any other expression position (a Paren, an Ok/Err wrapper, a Call/RecordConstruction argument, a BinOp operand, …)? Gates release-at-commit buffer threading (deps.__events) so a handler that never emits keeps byte-identical output, mirroring block_uses_send’s gate on deps.__exec.
match_needs_if_chain
A match needs the if/else-if lowering (ADR 0169) when any arm carries a guard or a refutable nested payload pattern — a JS switch on .tag can express neither. Flat, unguarded matches keep the switch (zero churn to existing output).
walk_block_exprs
walk_exprs
v0.22b: pre-order expression visitor — visits e, then every sub-expression, including statements and tails of nested blocks. Driven by ast::expr_children, the exhaustive total child iterator, rather than a hand-matched recursion duplicating it — a new ExprKind variant fails to compile in expr_children until it is taught to visit it, instead of silently under-visiting here.

Type Aliases§

EmbedIr
The payload of TypeShape::Sum’s own embeds — a resolved embeds clause ([DECISION C], #1161): the source type paired with the target variant’s own tag name. A plain tuple, not a dedicated struct, mirroring IrPat::Variant’s own fields: Vec<(String, Box<IrPat>)> precedent for a two-part fact with no further structure.
IndexIr
The payload of StoreFieldIr::indexed — one @indexed(by: …) key, identified by the indexed value-field’s own name ([DECISION C], #1163): referenced by the reference’s own StoreFieldIr.indexed: Vec<IndexIr> but never defined anywhere in the document, the same “referenced, not specified” gap #1161’s own Decision C named for EmbedIr. No dedicated struct: the sibling table’s own emitted shape (Record<string, string[]>) is fixed by the map’s own key type, not the indexed field’s, so the indexed field’s resolved type is not needed downstream — mirrors EmbedIr’s own “no further structure” precedent.