Skip to main content

Crate bynk_lower

Crate bynk_lower 

Source
Expand description

bynk-lower: the AST-analysis helpers bynk-emit reads resolved declaration-level facts through — handler kinds and given clauses, service protocols, store-field shapes, capability op and attached-method signatures, route cache/limit annotations, event-subscriber shapes, and the store-write walk behind emit_agent’s implicit-commit decision. Each takes a checked program (or its TypedCommons) and a syntax-tree node and returns a bynk_ir value; none lowers an expression body.

Reachability, corrected twice and now settled (Slice D0 of #1542, the IR cutover, closing summary in design/archive/retired-tracks.md). Through the crate carve (Arc D, P7.12) this paragraph claimed nothing here was reached from bynk-emit’s emission path; that was false — lower_event_subscriber_shapes_ir (called from bynk-emit/src/project.rs) went through lower_service_item_ir, which lowers every handler’s own body, so the whole recursive expression-lowering machinery (lower_service_handler_ir → lower_service_handler_body_ir → lower_block_ir → lower_expr_ir/ lower_stmt_ir) ran in production for every from Events(E) service and had its result discarded. Slice D0 repointed that one caller at the shape-only helpers it actually needs (see its own doc comment), so the original claim is now true by construction rather than false by oversight: every item constructor and the expression/statement/body lowering beneath it — lower_service_item_ir, lower_agent_item_ir, lower_provider_item_ir, lower_fn_item_ir, lower_type_item_ir, lower_capability_item_ir, the handler/store-field/commit-shape/ invariant/transition helpers, lower_fn_body_ir, lower_block_ir, lower_expr_ir and everything they call — has no caller outside this crate’s own test module. The 30 August 2026 review’s “zero callers” finding was right about the end state and wrong about the path; the track doc’s §10.2 has the trace. Slice D1 of the same track then deleted that machinery outright — 48 functions, the lowering context’s scope stack/temp counter/return-type/store-queryable fields, and every todo!() this crate ever carried — so rustc’s own dead-code analysis, not this paragraph, is the reachability record from here on. What stays is the AST-analysis helper vocabulary bynk-emit consumes today — lower_handler_kind_ir, lower_handler_given_ir, lower_protocol_ir{,_from_commons}, lower_type_shape_ir, lower_service_handler_signature_ir, body_writes_state, and their siblings — each with a production call site.

Totality discipline (ADR 0334, Q2), as it stands after Slice D1: the rule was “every entry point takes a certified &CheckedProgram, so a per-expression type lookup that misses is a compiler bug, not a recoverable state.” The per-expression lookup went with the expression lowering, so what the rule now governs is narrower: a helper that reads a declaration’s own type references still takes &CheckedProgram by default (lower_type_shape_ir’s doc comment has the full argument — a bare TypedCommons is not certified by construction), and the four that take a bare &TypedCommons instead — body_writes_state, lower_protocol_ir_from_commons, capability_op_sig_from_commons, lower_attached_fn_sig_ir_from_types — each document why their reads cannot reach a certification-dependent panic. The same discipline bynk-emit/src/emitter/emit.rs’s lower_workers_cross_context_call applies to its own bynk.emit.unresolved_cross_context_signature panic.

Functions§

body_writes_state
[DECISION B]/[DECISION C] (#1165): does body reach a mutating Callee::Store write, or an unconditional Statement::Assign (:=), anywhere — including inside a nested if/match/lambda? Drives, as of #1196 (the #1187 emitter-cutover track’s own R6.5 stake), emit_agent‘s (bynk-emit/src/emitter/emit.rs) real implicit-commit-wrapper decision (it also drove the IR-side CommitShape::Transactional decision until Slice D1 of #1542 deleted that constructor) — its previous own name-matching block_writes_state (emitter.rs) is deleted, this function is its sole, direct replacement. The walk’s own shape is that deleted function’s own already-correct skeleton reused structurally, not re-derived: Block/If/Match are hand-matched so crossing a nested block re-enters the statement-aware case (an expr_children descent alone flattens a block straight to its statements’ values, losing the Statement::Assign tag), everywhere else recurses over expr_children’s total child iterator.
capability_op_sig_from_commons
P6.29 (design/tracks/the-ir.md §6a): the TypedCommons-only counterpart to lower_capability_ops_ir, for call sites (emitter/lower.rs’s cap_op_param_names) that have a TypedCommons in hand but no CheckedProgram — LowerCtx/ModuleCtx never carry one (see lower_op_sig_ir_from_commons, this function’s own single-op sibling, for the identical reason it exists as a separate entry point rather than a thin wrapper over the CheckedProgram-driven lower_op_sig_ir).
is_effectful_return
P6.50 (design/tracks/the-ir.md §6b): a return type’s own syntactic Effect[...] wrapper — TypeRef::Effect(_, _), not the resolved Ty::Effect(_) shape lower_handler_signature_ir reads above via cx.program.ty_intern. Relocated here from emitter/emit.rs (its original home, #[allow(dead_code)]-free and with eight call sites across emit.rs/workers.rs/workers_entry.rs) because lower_service_handler_signature_ir below was already calling up into it (bynk_emit::emitter::is_effectful_return) — the Ast → Ir boundary running backwards, an Ir-side lowering function reaching into the emitter module it should only ever be called from. emit.rs and friends now call bynk_lower::is_effectful_return instead (relocated again at the P7.12 crate carve — emitter/ir::lower are now separate crates, bynk-emit/bynk-lower respectively).
lower_actor_seam_ir
#1187’s slice 3: a handler’s resolved actor-verification seam — the same “narrow, standalone reader of already-resolved data” precedent body_writes_state/lower_service_handler_signature_ir established, applied to bynk-check’s own five actor-seam resolvers (bynk-check/src/actors.rs) instead of a full handler assembly. [ActorSeamIr]’s own doc comment has the full grounding for the priority order and for the deliberately-missing Signature variant.
lower_attached_fn_sig_ir_from_types
P6.x (#1137): lower_fn_sig_ir_from_types over an entire MethodTable’s own instance + static entries — the attached-method gathering [bynk-emit’s build_emit_unit_ctx] needs for a uses-imported type. Filters to FnName::Method before lowering: ResolverMethodTable only ever collects attached methods in practice (bynk-check/src/resolver.rs’s own doc comment on MethodTable), but the filter stays as a defensive match rather than an assumption, matching the caller’s own pre-existing posture one step earlier — this just moves that posture in front of the lowering call instead of behind it, so the FnName read (and the filter itself) never has to leave this module.
lower_capability_ops_ir
A capability declaration’s resolved op signatures, in declaration order — what emitter.rs’s own capability-item loop reads (the caller already holds the capability’s name from the AST declaration). Slice 1 of #1542 split this out of a full IrItem::Capability constructor to end a build-then-discard-def round-trip; Slice D1 deleted that constructor.
lower_event_subscriber_shapes_ir
Every from Events(E) service in program’s own unit, captured as an [bynk_ir::EventSubscriberShape] keyed by service name — see that struct’s own doc comment for why this is captured now rather than re-derived cross-unit at compose time (P6.47, #1254).
lower_handler_given_ir
#1187’s slice 6 plumbing (sibling of lower_provider_given_ir): a handler’s own given clause, resolved standalone — the entry point for project.rs’s plan_agent_given_deps, EmitProjectCtx:: agent_method_givens, and emitter/workers.rs’s own given collection. Reuses lower_cap_ref_ir verbatim; a handler’s given is syntactically identical to a provider’s (bynk_syntax::ast::CapRef), so this is the same one-line adapter, not a new design.
lower_handler_kind_ir
P6.24a: pure, unconditional HandlerKind → [IrHandlerKind] conversion — every field is already fully resolved at parse time, so unlike almost every other function in this module this one takes no &CheckedProgram/&TypedCommons at all and can never miss.
lower_protocol_ir
P6.11 ([DECISION A], #1171): lower a service’s own from <protocol> header into a real [ProtocolIr] — standalone, takes the sub-node rather than the owning ServiceDecl (mirrors lower_store_field_shape_ir), so a from websocket/from Events fixture can pin the descriptor by itself.
lower_protocol_ir_from_commons
P6.24a: a TypedCommons-only sibling of lower_protocol_ir, the same split lower_op_sig_ir/lower_op_sig_ir_from_commons already established — for a call site holding only a unit’s own TypedCommons, never a &CheckedProgram (emitter.rs’s emit_project_imports, a header-import-collection pass that runs well outside the per-declaration emission loop any CheckedProgram is threaded through). Sound for the identical reason: nothing here reads a per-expression type, the one lookup whose .expect()-panic needed a genuinely certified program.
lower_provider_given_ir
A provider’s own given clause, resolved standalone — the entry point bynk-emit/src/project.rs’s instantiate_provider_ts_expr actually calls. This never touches the provider’s ops or their bodies; the full-provider assembly that did (and lowered every Bynk op body through the expression lowerer) had no caller and went with Slice D1 of #1542.
lower_route_cache_ir
#1228: a GET handler’s own @cache(maxAge:, scope:) freshness policy — [bynk_ir::CacheIr]’s own doc comment has the full grounding for why this is a standalone per-route reader. Field-for- field the same extraction emitter/workers_entry.rs’s own (now superseded) cache_policy_for did: only a GET yields a policy; project validation (bynk.http.cache_*) has already rejected a @cache anywhere else, and a malformed maxAge there, so a missing or ill-formed annotation here simply yields None — no &CheckedProgram needed, the same posture lower_policy_ir’s own doc comment already argues for: maxAge/scope are already-resolved syntactic literals (ExprKind::DurationLit/Ident), not a type this pass would ever need to resolve.
lower_route_limit_ir
#1228: a route’s own @limit(maxBody:) annotation, if present — the override half of emitter/workers_entry.rs’s own (now superseded) effective_max_body; the service-wide limits { maxBody } fallback stays that function’s own concern (read from a service’s limits {} block, not a per-route Handler, so it does not move here). Project validation (bynk.http.limit_*/limits_*) has already rejected a malformed or misplaced @limit, so an absent/ill-formed annotation here simply yields None — the caller’s own service-default fallback still applies. No &CheckedProgram needed, same reasoning as lower_route_cache_ir: maxBody is an already-resolved ExprKind::IntLit, not a type.
lower_service_handler_signature_ir
A service handler’s resolved signature — params/given/ret/ effectful — and never its body. This is what emit_service (bynk-emit/src/emitter/emit.rs) reads per handler, and what lower_event_subscriber_shapes_ir reads for a subscriber’s parameter count. Mirrors body_writes_state’s posture (#1196): a narrow, standalone reader of already-resolved data, applied to signature data instead of a body walk.
lower_store_field_shape_ir
A store field’s storage shape — its Cell/Map/Set/Cache/Log kind and @indexed keys (via store_field_kind_and_indexed), with init always None. This is the entry point emit_agent’s own state section actually needs; a Cell field’s zero/initial-value expression is rendered by the emitter from the AST, never lowered here. (An init-lowering sibling existed until Slice D1 of #1542; it lowered the initialiser through the deleted expression lowerer and had no caller.)
lower_type_shape_ir
A type declaration’s resolved structure as a [TypeShape] — the reader emitter.rs’s own type_shape_for calls directly. (Slice 1 of #1542 split this out of a full IrItem::Type constructor whose single field it was, ending a build-then-unreachable!-discard round-trip; Slice D1 then deleted that constructor, leaving this as the type reader.)

Type Aliases§

HandlerSignatureIr
(params, given, ret, effectful) — lower_service_handler_signature_ir’s return shape (#1187’s slice 5), a named alias rather than a bare tuple because its consumer (emit_service, bynk-emit/src/emitter/emit.rs) has to spell it out in a function signature. (The agent-handler signature reader that shared it went with Slice D1 of #1542.)