Skip to content

feat(supervisor): add first-class pool views with Option-returning get#2672

Open
slepp wants to merge 1 commit into
mainfrom
feat/supervisor-pool-accessors
Open

feat(supervisor): add first-class pool views with Option-returning get#2672
slepp wants to merge 1 commit into
mainfrom
feat/supervisor-pool-accessors

Conversation

@slepp

@slepp slepp commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Why

Supervisor pool accessors were fail-closed in two places: whole-field access on a ChildKind::Pool field (let workers = sup.workers) was rejected at HIR with SupervisorPoolChildAccessorUnsupported, and sup.pool.get(i) had no Option-returning form — only the trapping pool[i]. Both gaps were deferred from the earlier static-child accessor work; this completes the surface.

What

Pool accessors are now complete end-to-end via one substrate change — a first-class BuiltinType::SupervisorPool view type { LocalPid<S>, i64 pool_key }. The (supervisor, pool_key) pair travels as a typed runtime value, so len(), trapping [i], and get(i) all work on a bound view, not just the syntactic sup.pool.… form.

  • types/checker: Pool-kind field access types as SupervisorPool<S,T>; get(i) types as Option<LocalPid<T>>; pool indexed assignment and unknown pool methods are rejected with typed errors
  • HIR: the bare-pool fail-closed gate is deleted end-to-end (diagnostic variant, gate pass, hew-wasm mapping) — the construct is implemented, no compat shim
  • MIR: the former NotYetImplemented Pool arm emits RecordInit{ sup_handle, pool_key }; get routes the existing hew_supervisor_pool_child_get aggregate-return ABI through a hew_supervisor_pool_get_option terminator; the old span-rekeyed PoolAccessor side table shrinks to {kind}
  • codegen: lower_supervisor_pool_get_option_call materialises the registered tagged Option layout (Some=0 / None=1) via the shared enum-variant emission shell, mirroring the string/vec get-option precedent; all new error paths fail closed
  • ownership: LocalPid is a borrow handle (supervisor owns the actor) — no retain/release, same contract as the shipped static-child accessor

Test

  • supervisor_pool_get_option.hew fixture: exact stdout 84, proves Some-liveness via await worker.id() and None at both boundaries (get(-1), get(count))
  • supervisor_pool_field_access.hew fixture: exact stdout 37, whole-field pool view bound and used
  • hew-codegen-rs emission test pins store i8 0/store i8 1 for both Option arms and the payload-then-tag ordering
  • hew-mir actor tests assert RecordInit(SupervisorPool), the hew_supervisor_pool_child_get call, and the get-option terminator are all reached
  • hew-types adds pool_field_view_preserves_accessor_types_after_binding
  • Full workspace nextest green; fixture ratchet clean

Quality Checklist

  • PR title, body, and commit messages avoid internal-only orchestration/model vocabulary
  • No new .ok()? or unwrap_or_default() in codegen without // JUSTIFIED comment
  • New allocations have cleanup paths for sync, async, and actor shutdown contexts (no new allocations — the Some payload is a borrowed handle)
  • Serialization changes include round-trip encode/decode tests (no serialization changes)
  • New runtime features have WASM implementation or // WASM-TODO(#NNN): marker, and new hew_* exports are classified in scripts/jit-symbol-classification.toml (no new runtime exports — consumes the existing hew_supervisor_pool_child_get)
  • No duplicated logic — checked for existing helpers before adding new ones (Option construction reuses the shared enum-variant emission shell)

Out of scope

  • Restoring the multi-static-children compile test narrowed during the gate-test rewrite, and negative checker tests for pool indexed assignment / unknown pool methods — small follow-ups
  • Deduplicating the two hand-built {ptr, i64} SupervisorPool struct layouts (resolve_ty / record_struct_for) into a shared helper
  • The standing stale-handle-across-yield caveat on borrow handles is a documented substrate property, unchanged here

Bare sup.pool now yields a SupervisorPool<S,T> view supporting len(),
trapping [i], and get(i) -> Option<LocalPid<T>>; the former compile-time
rejections for whole-pool field access are removed. The (supervisor,
pool_key) pair travels as a typed runtime value, replacing the HIR
fail-closed gate and its span-rekeyed plumbing. LocalPid remains a
borrow handle — no retain/release.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant