Skip to main content

shape_value/
heap_variants.rs

1//! Single source of truth for HeapValue variants.
2//!
3//! `define_heap_types!` generates:
4//! - `HeapValue` enum
5//! - `HeapKind` enum (discriminant)
6//! - `HeapValue::kind()` method
7//! - `HeapValue::is_truthy()` method
8//! - `HeapValue::type_name()` method
9//!
10//! `equals()`, `structural_eq()`, and `Display` remain hand-written because
11//! they have complex per-variant logic (e.g. cross-type numeric comparison).
12//!
13//! Strict-typing bulldozer (Phase 2): every variant whose payload depended on
14//! the deleted `ValueWord` (the v1 dynamic-tag word) has been removed from
15//! `HeapValue`, along with the supporting `*Data` structs. The `HeapKind`
16//! discriminator preserves its ordinal numbering for ABI stability — gone
17//! variants now appear only in `HeapKind` (reserved). Heterogeneous-element
18//! collections (`HashMap`, `Set`, `Deque`, `PriorityQueue`), dynamic
19//! single-value wrappers (`Some`/`Ok`/`Err`/`Range`/`TraitObject`/
20//! `FunctionRef`), and dynamic capture/control-flow holders (`Iterator`,
21//! `Generator`, `Concurrency`, `Rare`, `Enum`, `Array`, `HostClosure`,
22//! `ProjectedRef`) are awaiting monomorphized typed replacements per
23//! `docs/runtime-v2-spec.md`.
24
25/// All HeapValue variant data lives here as a single source of truth.
26///
27/// Because Rust macro hygiene makes it impossible to use identifiers across
28/// macro boundaries (the `_v` in a pattern introduced by one macro cannot be
29/// referenced by tokens captured from a different call site), we define both
30/// the variant table AND the dispatch expressions in the SAME macro.
31///
32/// `define_heap_types!` takes no arguments — the variant table is embedded.
33/// The public types and `impl` blocks are generated inside the expansion.
34///
35/// Callers import this via `crate::define_heap_types!()`.
36#[macro_export]
37macro_rules! define_heap_types {
38    () => {
39        /// Discriminator for HeapValue variants, usable without full pattern match.
40        ///
41        /// One variant per surviving `HeapValue` arm — no dead variants
42        /// expressible. Trimmed in Phase 2b alongside the
43        /// `NativeKind::Ptr(HeapKind)` extension; see
44        /// `docs/defections.md` 2026-05-06 (HeapKind trim +
45        /// NativeKind::Ptr extension) for the audit findings and rejected
46        /// alternatives.
47        ///
48        /// The previous 77-variant surface (with `(removed)` /
49        /// `(deprecated)` annotations) preserved ordinals "for ABI
50        /// stability"; the bulldozer deleted the `tags.rs`
51        /// ordinal-stability test that made that contract load-bearing,
52        /// so the dead variants no longer had a justification to
53        /// remain in the source.
54        ///
55        // ADR-005: HeapKind is the canonical heap-shape discriminator.
56        // Layers above HeapValue take Arc<HeapValue> and dispatch on
57        // HeapValue::kind() rather than introducing parallel discriminators.
58        // See docs/adr/005-typed-slot-construction.md.
59        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ::serde::Serialize, ::serde::Deserialize)]
60        #[repr(u8)]
61        pub enum HeapKind {
62            String,        // 0
63            TypedObject,   // 1
64            Closure,       // 2  (matches HeapValue::ClosureRaw via the Closure ordinal)
65            Decimal,       // 3
66            BigInt,        // 4
67            DataTable,     // 5
68            Future,        // 6
69            TaskGroup,     // 7
70            TypedArray,    // 8  (VACATED: V3-S5 ckpt-1..ckpt-4 (2026-05-15)
71                           //      retired the `TypedArrayData` enum + outer
72                           //      `HeapValue::TypedArray(Arc<TypedArrayData>)`
73                           //      arm + `TypedBuffer<T>` / `AlignedTypedBuffer`
74                           //      wrapper layer per W12-typed-array-data-
75                           //      deletion-audit §3.5/§3.6/§B + ADR-006
76                           //      §2.7.24 Q25.A SUPERSEDED. Ordinal 8 is
77                           //      vacated; per audit §3.6 deprecation cadence
78                           //      + handover §0 ordinal-collision rule, the
79                           //      ordinal MUST NOT be reassigned to a new
80                           //      HeapKind variant — avoids grep-history
81                           //      confusion across future agent dispatch.
82                           //      The variant identifier itself stays in the
83                           //      enum until V3-S5 ckpt-5 deletes the
84                           //      4-table-lockstep dispatch arms (clone_with_kind
85                           //      / drop_with_kind / SharedCell::drop /
86                           //      TypedObjectStorage::drop_fields) and the
87                           //      identifier finally retires. Refusal #1
88                           //      binding: do not reintroduce under any
89                           //      rename/shim/bridge.
90            Temporal,      // 9
91            TableView,     // 10
92            Content,       // 11
93            Instant,       // 12
94            IoHandle,      // 13
95            NativeScalar,  // 14
96            NativeView,    // 15
97            Char,          // 16
98            HashMap,       // 17  (Stage C P1(b), 2026-05-07)
99            // Pure-discriminator variant — no corresponding `HeapValue` arm
100            // (FilterExpr payloads live as `Arc<FilterNode>` directly in slot
101            // bits, never wrapped in `HeapValue`). Added to fix the
102            // type-confusion soundness gap surfaced by Wave-α D-raw-helpers
103            // (commit `a27c0e4`): the filter-expression branch of
104            // `executor/logical/mod.rs` previously reused
105            // `HeapKind::NativeView` to label `Arc<FilterNode>` payloads,
106            // and the runtime `clone_with_kind` / `drop_with_kind` tables
107            // dispatched the same label as `Arc<NativeViewData>` —
108            // wrong-type retain/release. ADR-006 §2.3 / §2.7.6 / Q8
109            // amendment (Wave-γ G-heap-filter-expr).
110            FilterExpr,    // 18  (Wave-γ G-heap-filter-expr, 2026-05-09)
111            // ADR-006 §2.7.13 / Q14 (Wave 8 W8-T26, 2026-05-10):
112            // Reference-value carrier — replaces the deleted
113            // `nanboxed::RefTarget` / `RefProjection` `ValueWord`-shaped
114            // enum. Slot bits are `Arc::into_raw(Arc<RefTarget>) as u64`
115            // directly (mirror of FilterExpr's pure-discriminator-style
116            // dispatch — `as_heap_value()` is undefined on
117            // Reference-labeled bits; recovery is `Arc::from_raw::
118            // <RefTarget>(bits)`). The `clone_with_kind` /
119            // `drop_with_kind` dispatch tables retain/release
120            // `Arc<RefTarget>` directly, NOT through `HeapValue`. The
121            // `HeapValue::Reference` arm below exists ONLY to preserve
122            // the ADR-005 §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue`
123            // symmetry property; no caller materializes a `Reference`
124            // through `HeapValue` pattern matching.
125            Reference,     // 19  (Wave 8 W8-T26, 2026-05-10)
126            // Pure-discriminator variant — no corresponding `HeapValue` arm
127            // (`Arc<SharedCell>` cell-pointer slots live as
128            // `Arc::into_raw(Arc<SharedCell>) as u64` directly in the
129            // kinded stack / module-binding store / cell-storage slots,
130            // never wrapped in `HeapValue`). Added so the §2.7.7 / §2.7.8
131            // parallel-kind tracks can label `*const SharedCell` slots
132            // distinctly — the precondition for unblocking
133            // `op_alloc_shared_local` / `op_alloc_shared_module_binding`.
134            // Same pure-discriminator role as `HeapKind::FilterExpr`:
135            // `as_heap_value()` is unsound on `SharedCell`-labeled bits;
136            // heap dispatch goes through the kind label, not through
137            // `HeapValue` materialisation. ADR-006 §2.7.12 / Q13 amendment
138            // (Wave 8 W8-T25, mirror of §2.7.9 FilterExpr precedent).
139            // NOTE: ordinal 20 (not the originally drafted 19) — T26 took
140            // 19 first at merge time.
141            SharedCell,    // 20  (Wave 8 W8-T25, 2026-05-10)
142            // ADR-006 §2.7.15 / Q16 amendment (Wave 13 W13-hashset-rebuild,
143            // 2026-05-10): one-keyspace Set carrier, structurally a mirror
144            // of the Stage C P1(b) `HeapKind::HashMap(Arc<HashMapData>)`
145            // shape with the values buffer dropped. Full HeapValue arm
146            // (NOT pure-discriminator like FilterExpr / SharedCell): Set
147            // values flow through `slot.as_heap_value()` for receiver
148            // classification at method dispatch (`set.add(...)` /
149            // `set.has(...)` / `set.union(other)`), can be stored in
150            // TypedObject slots and `the-deleted-heterogeneous-element-carrier` buffers.
151            // See §2.7.15 for the full justification + the rejected Path
152            // B (`TypedSet<T>` per element kind) alternative.
153            HashSet,       // 21  (Wave 13 W13-hashset-rebuild, 2026-05-10)
154            // ADR-006 §2.7.16 / Q17 (W13-iterator-state, 2026-05-10):
155            // Lazy-iterator carrier — replaces the deleted
156            // `heap_value::IteratorState` / `IteratorTransform`
157            // `ValueWord`-shaped enums. Slot bits are
158            // `Arc::into_raw(Arc<IteratorState>) as u64`; unlike
159            // FilterExpr / Reference / SharedCell, the matching
160            // `HeapValue::Iterator(Arc<IteratorState>)` arm IS used at
161            // runtime — iterator method handlers recover the typed Arc
162            // via `slot.as_heap_value()` per ADR-005 §1
163            // single-discriminator. The `clone_with_kind` /
164            // `drop_with_kind` dispatch tables retain/release
165            // `Arc<IteratorState>` directly, NOT through the
166            // `HeapValue` arm (mirror of other typed-Arc
167            // refcount-dispatch arms — refcount discipline goes
168            // through the kind label).
169            Iterator,      // 22  (W13-iterator-state, 2026-05-10)
170            // ADR-006 §2.7.19 / Q20 amendment (Wave 15 W15-deque,
171            // 2026-05-10): heterogeneous-element double-ended queue
172            // carrier, structurally a mirror of the §2.7.15 HashSet
173            // shape with the dedup keyspace replaced by a
174            // VecDeque<Arc<HeapValue>>. Full HeapValue arm (NOT
175            // pure-discriminator like FilterExpr / SharedCell): Deque
176            // values flow through `slot.as_heap_value()` for receiver
177            // classification at method dispatch (`d.pushBack(...)` /
178            // `d.popFront()` / `d.size()`). Ordinal 23 (not the
179            // originally drafted 26) — W14 / W15-priority-queue have
180            // not landed at this branch's parent (`bb0ccc3`); per
181            // playbook §0 ordinal-bump rule, the next free slot
182            // after Iterator=22 is taken. Merge ordering at
183            // integration time per playbook §4 (W14 → PriorityQueue
184            // → Deque) restores the documented 26 spec layout.
185            Deque,         // 23  (Wave 15 W15-deque, 2026-05-10)
186            // ADR-006 §2.7.20 / Q21 amendment (Wave 15 W15-channel-rebuild,
187            // 2026-05-10): MPSC-style synchronous channel concurrency
188            // primitive. Unlike HashMap/HashSet/Iterator (which are
189            // immutable-on-clone with `Arc::make_mut` clone-on-write),
190            // `ChannelData` carries interior mutability via
191            // `Mutex<ChannelInner>` so two `Arc<ChannelData>` shares of
192            // the same channel observe each other's `send` / `recv`
193            // mutations (the producer/consumer-endpoints shape).
194            // Sync same-thread `send` / `try_recv` / `close` / `is_closed`
195            // land here; blocking `recv()` (cross-task await-style) is
196            // the §2.7.4 task-scheduler boundary and is SURFACE'd at
197            // the method body — see `executor/objects/channel_methods.rs`.
198            // Full HeapValue arm (NOT pure-discriminator) — Channel
199            // values flow through `slot.as_heap_value()` for receiver
200            // classification at method dispatch (`c.send(...)` / `c.recv()`),
201            // can be stored in TypedObject slots and `the-deleted-heterogeneous-element-carrier`
202            // buffers.
203            Channel,       // 24  (Wave 15 W15-channel-rebuild, 2026-05-10; bumped from drafted 23 at merge — Deque already took 23)
204            // ADR-006 §2.7.18 / Q19 amendment (Wave 15 W15-priority-queue,
205            // 2026-05-10): i64-priority min-heap carrier, structurally
206            // a mirror of the §2.7.15 HashSet shape with the keys
207            // buffer carrying i64 priorities instead of `Arc<String>`.
208            // Full HeapValue arm (NOT pure-discriminator like FilterExpr
209            // / SharedCell): PriorityQueue values flow through
210            // `slot.as_heap_value()` for receiver classification at
211            // method dispatch (`pq.push(...)` / `pq.pop()` /
212            // `pq.peek()`). See `$crate::heap_value::PriorityQueueData`
213            // for the storage shape and §2.7.18 for the full
214            // justification + the rejected typed-payload alternative.
215            // Pre-assigned ordinal 25 per the wave-14-15-16 playbook
216            // (no bump needed at landing).
217            PriorityQueue, // 25  (Wave 15 W15-priority-queue, 2026-05-10)
218            // W15-range (ADR-006 §2.7.23 / Q24, 2026-05-10): Range value
219            // carrier — `start..end` and `start..=end` surface syntax build
220            // `Arc<RangeData>` slots. Distinct from `HeapKind::Iterator`
221            // (which models the post-`.iter()` stateful pipeline): Range is
222            // a value with identity (`r.start`, `r.contains(x)`, prints as
223            // `0..10`), Iterator is a cursor-bearing pipeline. The
224            // `Range.iter()` receiver method converts `RangeData` to
225            // `IteratorState { source: IteratorSource::Range { start, end,
226            // step } }`, where `IteratorSource::Range` was already provided
227            // by W13-iterator-state for forward compatibility. Full
228            // HeapValue arm (NOT pure-discriminator like FilterExpr /
229            // SharedCell): Range values flow through `slot.as_heap_value()`
230            // for receiver classification at method dispatch.
231            //
232            // Ordinal 30 chosen at W14-15-16 fan-out per the playbook
233            // §0 "Pre-assigned HeapKind ordinals" table. Slots 23 (Result),
234            // 24 (Option), 25 (PriorityQueue), 26 (Deque), 27 (Channel),
235            // 28 (Column), 29 (Matrix) reserved for W14/W15 sibling agents.
236            Range,         // 26  (W15-range, 2026-05-10; renumbered from drafted 30 at merge — Result/Option/Column/Matrix slots dissolved or audit-pivoted)
237            // ADR-006 §2.7.17 / Q18 amendment (Wave 14 W14-variant-codegen,
238            // 2026-05-10): Result<T,E> carrier — replaces the deleted
239            // pre-bulldozer `Some/Ok/Err` `ValueWord`-shaped HeapValue
240            // arms. Slot bits are `Arc::into_raw(Arc<ResultData>)`. Full
241            // `HeapValue::Result(Arc<ResultData>)` arm: variant
242            // discriminators (`op_is_ok` / `op_is_err`) and unwrap
243            // operations (`op_unwrap_ok` / `op_unwrap_err` /
244            // `op_try_unwrap`) recover the typed Arc via
245            // `slot.as_heap_value()` per ADR-005 §1 single-discriminator.
246            // Mirror of §2.7.16 Iterator typed-Arc shape (full
247            // HeapValue arm, NOT pure-discriminator like §2.7.9
248            // FilterExpr / §2.7.12 SharedCell).
249            Result,        // 27  (Wave 14 W14-variant-codegen, 2026-05-10; renumbered from drafted 23 at merge — Deque already took 23)
250            // ADR-006 §2.7.17 / Q18 amendment (Wave 14 W14-variant-codegen,
251            // 2026-05-10): Option<T> carrier — sibling of Result with
252            // `is_some` discriminator instead of `is_ok`. The dual-shape
253            // representation (vs null-coding `Some(x) ≡ x`, `None ≡ null
254            // sentinel`) is required because `SomeCtor` may take a
255            // null-bearing `T?` payload, which cannot be distinguished
256            // from None under null-coding. Slot bits are
257            // `Arc::into_raw(Arc<OptionData>)`; full HeapValue arm.
258            Option,        // 28  (Wave 14 W14-variant-codegen, 2026-05-10; renumbered from drafted 24 at merge — Channel already took 24)
259            // ADR-006 §2.7.24 / Q25.C amendment (Wave 17
260            // W17-trait-object-storage, 2026-05-11): re-introduces the
261            // strict-typing-bulldozer-deleted `HeapKind::TraitObject` /
262            // `HeapValue::TraitObject` carrier as a typed-Arc pair
263            // (`Arc<TraitObjectStorage>`) replacing the legacy
264            // `HeapValue::TraitObject { value: Box<u64>, vtable: Arc<VTable> }`
265            // shape. The new carrier is a fat-pointer over an
266            // `Arc<TypedObjectStorage>` data half + an `Arc<VTable>`
267            // vtable half — universal-dyn auto-boxing (§Q25.C.1) makes
268            // the boxed value always a TypedObject, so the `Box<u64>`
269            // kind-blind raw-bits shape is refused under §Q25.E #3.
270            //
271            // Full HeapValue arm (NOT pure-discriminator like
272            // FilterExpr / SharedCell / Reference): TraitObject values
273            // flow through `slot.as_heap_value()` for receiver
274            // classification at method dispatch (`a.name()` /
275            // `a.clone_me()` etc. — the universe of `dyn T` method
276            // calls). Same dispatch shape as the §2.7.20 Channel
277            // precedent for refcount discipline; `clone_with_kind` /
278            // `drop_with_kind` retain/release
279            // `Arc<TraitObjectStorage>` directly via the kind label,
280            // NOT through `HeapValue`.
281            //
282            // Pre-assigned ordinal 29 per the wave-2.5 W17-trait-object
283            // dispatch contract (the original W17-typed-carrier-mono
284            // playbook reserved 29 for TraitObject; rescope kept that
285            // assignment). Ordinal 29 was free between Option=28 and
286            // the W17-concurrency block Mutex=30 / Atomic=31 / Lazy=32.
287            TraitObject,   // 29  (Wave 17 W17-trait-object-storage, 2026-05-11)
288            // ADR-006 §2.7.25 amendment (Wave 17 W17-concurrency,
289            // 2026-05-11): Mutex<T> concurrency primitive — a single
290            // typed payload protected by a `Mutex<MutexInner>` for
291            // interior-mutability sharing (mirror of §2.7.20 Channel's
292            // `Mutex<ChannelInner>` shape — two `Arc<MutexData>` shares
293            // observe each other's `set` mutations). Distinct from
294            // §2.7.12 `HeapKind::SharedCell` (which is binding-storage
295            // interior-mutability for `var` binding-form values) —
296            // `MutexData` is a runtime synchronization primitive user
297            // code asks for explicitly. Full HeapValue arm (NOT
298            // pure-discriminator like FilterExpr / SharedCell): Mutex
299            // values flow through `slot.as_heap_value()` for receiver
300            // classification at method dispatch (`m.lock()` / `m.set(...)`),
301            // can be stored in TypedObject slots. Pre-assigned ordinal
302            // 30 per the wave-2.5 W17-concurrency dispatch contract.
303            Mutex,         // 30  (Wave 17 W17-concurrency, 2026-05-11)
304            // ADR-006 §2.7.25 amendment (Wave 17 W17-concurrency,
305            // 2026-05-11): Atomic<i64> concurrency primitive — wraps
306            // `std::sync::atomic::AtomicI64` for atomic load / store /
307            // fetch_add / fetch_sub / compare_exchange operations.
308            // i64-only at landing per the playbook's "typed-payload
309            // deferral" precedent (W15-priority-queue i64-priority-only,
310            // W13-hashset string-only); typed-payload `Atomic<T>` is a
311            // future Phase-2c amendment with measurement. Full HeapValue
312            // arm — Atomic values flow through `slot.as_heap_value()`
313            // for receiver classification at method dispatch.
314            // Pre-assigned ordinal 31 per the wave-2.5 W17-concurrency
315            // dispatch contract.
316            Atomic,        // 31  (Wave 17 W17-concurrency, 2026-05-11)
317            // ADR-006 §2.7.25 amendment (Wave 17 W17-concurrency,
318            // 2026-05-11): Lazy<T> initialize-once carrier — wraps an
319            // initializer closure (`KindedSlot` of kind
320            // `Ptr(HeapKind::Closure)`) and a cached value slot.
321            // Closure-call path unlocked by W17-make-closure (merged
322            // at `aa47364`). Mirror of §2.7.20 Channel's
323            // `Mutex<inner>` shape so concurrent `get()` calls
324            // serialize cleanly when the runtime grows real
325            // concurrency. Full HeapValue arm — Lazy values flow
326            // through `slot.as_heap_value()` for receiver
327            // classification at method dispatch (`l.get()` /
328            // `l.is_initialized()`). Pre-assigned ordinal 32 per the
329            // wave-2.5 W17-concurrency dispatch contract.
330            Lazy,          // 32  (Wave 17 W17-concurrency, 2026-05-11)
331            // ADR-006 §2.7.26 amendment (Wave 17 W17-comptime-vm-dispatch,
332            // 2026-05-12): module-function reference carrier — labels a
333            // slot whose `bits` are a `module_fn_id: usize` cast to `u64`.
334            // Pure-discriminator variant (no corresponding `HeapValue`
335            // arm); inline-scalar payload (no `Arc<T>`, no heap state) —
336            // same shape as `HeapKind::Future` and `HeapKind::Char`.
337            // `clone_with_kind` / `drop_with_kind` are no-ops on this
338            // arm. Used by `populate_module_objects` to encode the
339            // `__comptime__` (and any other extension) module's typed-
340            // object field references that the compiled bytecode chain
341            // `LoadModuleBinding + GetFieldTyped + CallValue` dispatches
342            // through to `invoke_module_fn_id_stub`. See
343            // `executor/vm_impl/modules.rs::populate_module_objects` for
344            // the construction-side contract and
345            // `executor/call_convention.rs::call_value_immediate_nb`
346            // (`NativeKind::Ptr(HeapKind::ModuleFn)` arm) for the
347            // dispatch-side contract. `as_heap_value()` is unsound on
348            // `ModuleFn`-labeled bits (mirror of FilterExpr /
349            // SharedCell / Reference's pure-discriminator-style
350            // dispatch).
351            ModuleFn,      // 33  (Wave 17 W17-comptime-vm-dispatch, 2026-05-12)
352            // ADR-006 §2.7.22 amendment (Round 18 S3
353            // W12-matrix-floatslice-heapkind-exit, 2026-05-13): Matrix exits
354            // the `TypedArrayData` carrier hierarchy. The pre-amendment
355            // Q23 ruling (Matrix lives under `HeapKind::TypedArray` via
356            // `TypedArrayData::Matrix(Arc<MatrixData>)`) is superseded by
357            // the Round 17 deletion-audit + cluster-0-transition
358            // strategic-owner authorization (2026-05-13): Matrix is a
359            // single-Matrix value (category-correctness), not a
360            // buffer-of-Matrix.
361            //
362            // Full `HeapValue::Matrix(Arc<MatrixData>)` arm exists for the
363            // ADR-005 §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry,
364            // but Matrix slot bits are
365            // `Arc::into_raw(Arc<MatrixData>) as u64` directly (typed-Arc
366            // shape, mirror of FilterExpr / Reference's pure-discriminator
367            // dispatch — NOT a `Box<HeapValue>` wrap); calling
368            // `slot.as_heap_value()` on a Matrix-labeled slot is
369            // undefined behavior. `clone_with_kind` / `drop_with_kind`
370            // dispatch the matching `Arc::increment/decrement_strong_count
371            // ::<MatrixData>` retain/release directly via the kind label.
372            //
373            // The §2.7.9 / §2.7.12 / §Q23 single-discriminator concern
374            // that motivated Q23's parallel-HeapKind-refusal is addressed
375            // by ADR-005 §1's exception clause: `HeapKind::Matrix` is NOT
376            // parallel to `HeapKind::TypedArray` (which is the
377            // array-buffer carrier with element-typed payload); Matrix is
378            // a separate value category (a structured numeric matrix
379            // value, not an array of anything).
380            Matrix,        // 34  (Round 18 S3 W12-matrix-floatslice-heapkind-exit, 2026-05-13)
381            // ADR-006 §2.7.22 amendment (Round 18 S3
382            // W12-matrix-floatslice-heapkind-exit, 2026-05-13): the
383            // `FloatSlice { parent, offset, len }` projection (returned by
384            // `Matrix.row(i)` / `Matrix.col(i)`) exits the
385            // `TypedArrayData` carrier hierarchy for the same
386            // category-correctness reason as `HeapKind::Matrix` — it is a
387            // projection-into-a-Matrix, not a buffer of floats. The new
388            // payload struct is `MatrixSliceData { parent: Arc<MatrixData>,
389            // offset: u32, len: u32 }` preserving the
390            // alias-into-parent-buffer semantics from the pre-amendment
391            // shape.
392            //
393            // Same dispatch shape as `HeapKind::Matrix`: typed-Arc
394            // pure-discriminator (slot bits =
395            // `Arc::into_raw(Arc<MatrixSliceData>)`, retain/release through
396            // the kind label, `as_heap_value()` unsound, full
397            // `HeapValue::MatrixSlice(Arc<MatrixSliceData>)` arm for the
398            // ADR-005 §1 / ADR-006 §2.3 symmetry property).
399            MatrixSlice,   // 35  (Round 18 S3 W12-matrix-floatslice-heapkind-exit, 2026-05-13)
400        }
401
402        /// Compact heap-allocated value. Strict-typed variants only — every
403        /// payload is either a typed primitive (`i64`, `char`, `f64` via
404        /// `TypedArray`), a typed structure (`TypedObject` slots, typed FFI
405        /// pointers, typed temporal data), or a typed handle.
406        ///
407        /// Variants whose payloads depended on the deleted `ValueWord`
408        /// dynamic word were removed in the strict-typing Phase-2 bulldozer.
409        /// See the corresponding `HeapKind` ordinals (annotated "(removed)")
410        /// for the migration target.
411        ///
412        // ADR-005: HeapValue is the single discriminator for heap-resident
413        // values. New variants are added here when a new heap shape is
414        // genuinely required; layers above (ConcreteReturn, TypedFieldValue,
415        // marshal helpers, JIT FFI carriers) must NOT introduce parallel
416        // sum types whose variants project 1:1 to HeapKind. The single
417        // explicit exception is `TypedFieldValue::String(Arc<String>)`, named
418        // and bounded in ADR-005. See docs/adr/005-typed-slot-construction.md.
419        // ADR-006 §2.3: each heap-resident variant carries a typed
420        // `Arc<T>` payload (single atomic refcount bump on clone, single
421        // decrement on drop, no `Box<HeapValue>` wrapping). Inline scalars
422        // (`Future(u64)`, `Char(char)`, `NativeScalar`) stay inline because
423        // their payloads fit in a register and have no heap state.
424        // `ClosureRaw` continues to use `OwnedClosureBlock` because that
425        // type already manages its own refcount via the v2 typed-closure
426        // header. See docs/adr/006-value-and-memory-model.md §2.3.
427        #[derive(Debug)]
428        pub enum HeapValue {
429            // ===== Typed primitives =====
430            String(std::sync::Arc<String>),
431            // ADR-006 §2.3: `Decimal` is 16 bytes inline; wrapping in `Arc`
432            // shrinks the enum payload to a pointer so the slot's clone is
433            // a single atomic increment.
434            Decimal(std::sync::Arc<rust_decimal::Decimal>),
435            // ADR-006 §2.3: `BigInt`'s inner `i64` is the v2 placeholder
436            // for an arbitrary-precision integer. Wrapping in `Arc` keeps
437            // the variant cheap to clone today and gives the Drop discipline
438            // a single typed `Arc::decrement_strong_count::<i64>` site for
439            // when the payload widens to a real big-int representation.
440            BigInt(std::sync::Arc<i64>),
441            // Future-id is an inline scalar — no heap state.
442            Future(u64),
443            // Char is an inline scalar — no heap state.
444            Char(char),
445            // ===== Typed handles / data stores =====
446            DataTable(std::sync::Arc<$crate::datatable::DataTable>),
447            // ADR-006 §2.3: `Box<ContentNode>` migrated to `Arc<ContentNode>`
448            // so clones are an atomic refcount bump rather than a deep copy.
449            Content(std::sync::Arc<$crate::content::ContentNode>),
450            // ADR-006 §2.3: `Box<Instant>` migrated to `Arc<Instant>`. The
451            // inner `Instant` is `Copy` but the boxing cost was paid at
452            // every clone; the Arc bump replaces it.
453            Instant(std::sync::Arc<std::time::Instant>),
454            IoHandle(std::sync::Arc<$crate::heap_value::IoHandleData>),
455            // NativeScalar is `Copy` and ≤ 16 bytes — kept inline.
456            NativeScalar($crate::heap_value::NativeScalar),
457            // ADR-006 §2.3: `Box<NativeViewData>` migrated to
458            // `Arc<NativeViewData>` to match `from_native_view(Arc<…>)`.
459            NativeView(std::sync::Arc<$crate::heap_value::NativeViewData>),
460            // ===== Struct variants =====
461            /// Object value with schema-defined typed slots.
462            ///
463            // ADR-006 §2.3: payload was `Arc<TypedObjectStorage>` post the
464            // first §2.3 amendment. Wave 2 Round 4 D4 ckpt-final-prime²
465            // (2026-05-14): payload flipped to `TypedObjectPtr`
466            // (`#[repr(transparent)]` newtype around
467            // `*const TypedObjectStorage`) per the §2.3 amendment + Path B
468            // ratification. The newtype owns one v2-raw HeapHeader-at-offset-0
469            // refcount share; Clone bumps via `v2_retain`, Drop retires via
470            // `TypedObjectStorage::release_elem`. Auto-derived Drop/Clone/
471            // Send/Sync on `HeapValue` chain through the wrapper's manual
472            // discipline. See docs/adr/006-value-and-memory-model.md §2.3.
473            TypedObject($crate::heap_value::TypedObjectPtr),
474            /// Track A.5 — the canonical closure representation.
475            ///
476            /// Raw `TypedClosureHeader`-backed closure. Captures live in a
477            /// typed C-laid-out block allocated by
478            /// `closure_raw::alloc_typed_closure` and owned by the embedded
479            /// [`OwnedClosureBlock`]. Cloning / dropping this variant
480            /// manages the block's refcount in lockstep with the enclosing
481            /// `Arc<HeapValue>`. Readers go through `VmClosureHandle` for
482            /// the stable read API. There is no legacy fallback.
483            ClosureRaw($crate::v2::closure_raw::OwnedClosureBlock),
484            // ADR-006 §2.3: `TaskGroup { kind, task_ids }` struct variant
485            // collapsed to a single-tuple `Arc<TaskGroupData>` payload so
486            // every heap variant follows the typed-Arc shape. Field reads
487            // are now `tg.kind` / `tg.task_ids` (Phase 1.B caller migration).
488            TaskGroup(std::sync::Arc<$crate::heap_value::TaskGroupData>),
489            // ===== Consolidated wrapper variants =====
490            // V3-S5 ckpt-4 (2026-05-15): `TypedArray(Arc<TypedArrayData>)`
491            // arm DELETED. The inner `TypedArrayData` enum was retired at
492            // V3-S5 ckpt-1 (heap_value.rs:2877-3052 wholesale deletion per
493            // W12-typed-array-data-deletion-audit §3.5 / §B + ADR-006
494            // §2.7.24 Q25.A SUPERSEDED). With no inner payload to wrap,
495            // the outer `HeapValue::TypedArray(...)` arm is now orphan and
496            // is deleted in lockstep. The `HeapKind::TypedArray = 8`
497            // ordinal becomes a "vacated ordinal" comment marker (see the
498            // HeapKind table earlier in this file). 4-table-lockstep
499            // dispatch arms for `HeapKind::TypedArray` (clone_with_kind /
500            // drop_with_kind / SharedCell::drop /
501            // TypedObjectStorage::drop_fields) are deleted at V3-S5 ckpt-5
502            // territory per supervisor 2026-05-15 partition.
503            //
504            // Refusal #1 binding: do not resurrect this arm under any
505            // rename/shim/bridge — see CLAUDE.md "Forbidden code" +
506            // "Renames to refuse on sight" broader-family regex.
507            // ADR-006 §2.3: `TemporalData` enum was inline (size = largest
508            // variant ≈ 32 bytes including `Box`'s overhead). `Arc` reduces
509            // the slot payload to a single pointer.
510            Temporal(std::sync::Arc<$crate::heap_value::TemporalData>),
511            // ADR-006 §2.3: `TableViewData` enum migrated to `Arc<…>` to
512            // match the canonical typed-Arc shape; its arms already carry
513            // `Arc<DataTable>` internally.
514            TableView(std::sync::Arc<$crate::heap_value::TableViewData>),
515            // ===== Stage C HashMap-marshal P1(b) =====
516            /// HashMap with string keys + per-V monomorphized values.
517            ///
518            /// **Wave 2 Round 3b C2-joint ckpt-2 (2026-05-14):** payload flipped
519            /// from `Arc<HashMapData>` (non-generic) to `HashMapKindedRef`
520            /// (per-V enum carrier) per ADR-006 §2.7.24 Q25.B SUPERSEDED +
521            /// audit §C.4 option (a.2). The variant tag IS the per-V
522            /// `NativeKind` discriminator; per-V dispatch at consumer sites
523            /// goes through the `HashMapKindedRef::{I64, F64, Bool, Char,
524            /// String, Decimal, TypedObject, TraitObject}` arms.
525            ///
526            /// See `$crate::heap_value::HashMapData<V>` + `HashMapKindedRef`
527            /// for the storage shape. Stage C P1(b), 2026-05-07.
528            HashMap($crate::heap_value::HashMapKindedRef),
529            // ===== Wave-γ G-heap-filter-expr (2026-05-09) =====
530            /// Filter-expression tree (`Arc<FilterNode>`) used by the query
531            /// DSL's `And` / `Or` / `Not` opcodes (`executor/logical/mod.rs`).
532            /// In current code FilterExpr payloads are emitted directly to
533            /// the kinded stack as `Arc::into_raw(Arc<FilterNode>) as u64`
534            /// with kind `NativeKind::Ptr(HeapKind::FilterExpr)` and never
535            /// wrapped in `HeapValue`. The arm exists to preserve the
536            /// ADR-005 §1 invariant that every `HeapKind` discriminator has
537            /// a `HeapValue` arm of the same shape — kind() / is_truthy() /
538            /// type_name() / drop_with_kind() / clone_with_kind() must
539            /// dispatch a `HeapKind::FilterExpr` slot as `Arc<FilterNode>`,
540            /// not `Arc<NativeViewData>` (the pre-Wave-γ type-confusion gap
541            /// surfaced by Wave-α D-raw-helpers, commit `a27c0e4`).
542            FilterExpr(std::sync::Arc<$crate::value::FilterNode>),
543            // ===== Wave 13 W13-hashset-rebuild (ADR-006 §2.7.15 / Q16,
544            // 2026-05-10) =====
545            /// One-keyspace Set carrier. Mirror of
546            /// `HeapValue::HashMap(Arc<HashMapData>)` with the values
547            /// buffer dropped: insertion-ordered `Arc<TypedBuffer<Arc<
548            /// String>>>` keys + eager FNV-1a bucket index for O(1)
549            /// `set.has(key)`. See `$crate::heap_value::HashSetData` for
550            /// the storage shape.
551            ///
552            /// Full HeapValue arm (NOT pure-discriminator like FilterExpr
553            /// / SharedCell): Set values flow through `as_heap_value()`
554            /// for method-receiver classification per the §2.7.15 amendment.
555            HashSet(std::sync::Arc<$crate::heap_value::HashSetData>),
556            // ===== Wave 8 W8-T26 (ADR-006 §2.7.13 / Q14, 2026-05-10) =====
557            /// Reference-value carrier (`Arc<RefTarget>`) used by the
558            /// `MakeRef` / `MakeFieldRef` / `MakeIndexRef` /
559            /// `DerefLoad` / `DerefStore` / `SetIndexRef` opcode family
560            /// (`executor/variables/mod.rs`). In current code Reference
561            /// payloads are emitted directly to the kinded stack as
562            /// `Arc::into_raw(Arc<RefTarget>) as u64` with kind
563            /// `NativeKind::Ptr(HeapKind::Reference)` and never wrapped
564            /// in `HeapValue`. The arm exists to preserve the ADR-005
565            /// §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry — same
566            /// pattern as `HeapValue::FilterExpr` (§2.7.9). Calling
567            /// `slot.as_heap_value()` on a Reference-labeled slot is
568            /// undefined behavior; the canonical recovery is
569            /// `Arc::from_raw::<RefTarget>(bits)`.
570            Reference(std::sync::Arc<$crate::reference::RefTarget>),
571            // ===== W13-iterator-state (ADR-006 §2.7.16 / Q17, 2026-05-10) =====
572            /// Lazy iterator pipeline carrier (`Arc<IteratorState>`).
573            /// Used by `Array.iter` / `String.iter` / `HashMap.iter` /
574            /// `Range.iter` factories and the `ITERATOR_METHODS` PHF
575            /// (`map` / `filter` / `take` / `skip` / `flatMap` /
576            /// `enumerate` / `chain` / `collect` / `forEach` /
577            /// `reduce` / `count` / `any` / `all` / `find`). Slot bits
578            /// are `Arc::into_raw(Arc<IteratorState>) as u64`; recovery
579            /// goes through `slot.as_heap_value()` →
580            /// `HeapValue::Iterator(arc)` per ADR-005 §1
581            /// single-discriminator (the lazy-transforms / source /
582            /// cursor triple is opaque at the dispatch shell —
583            /// terminals walk `arc.transforms` and dispatch per stage).
584            Iterator(std::sync::Arc<$crate::iterator_state::IteratorState>),
585            // ===== Wave 15 W15-deque (ADR-006 §2.7.19 / Q20, 2026-05-10) =====
586            /// Double-ended queue carrier. Structurally a mirror of
587            /// `HeapValue::HashSet(Arc<HashSetData>)` with the dedup
588            /// keyspace replaced by a `VecDeque<Arc<HeapValue>>`
589            /// (heterogeneous-element, order-preserving, no
590            /// deduplication). See `$crate::heap_value::DequeData` for
591            /// the storage shape.
592            ///
593            /// Full HeapValue arm (NOT pure-discriminator like
594            /// FilterExpr / SharedCell): Deque values flow through
595            /// `as_heap_value()` for receiver classification per the
596            /// §2.7.19 amendment.
597            Deque(std::sync::Arc<$crate::heap_value::DequeData>),
598            // ===== Wave 15 W15-channel-rebuild (ADR-006 §2.7.20 / Q21,
599            // 2026-05-10) =====
600            /// MPSC-style synchronous channel carrier (`Arc<ChannelData>`).
601            /// Unlike HashMap/HashSet (immutable-on-clone with
602            /// `Arc::make_mut` clone-on-write), `ChannelData` wraps a
603            /// `Mutex<ChannelInner>` so two `Arc<ChannelData>` shares
604            /// of the same channel observe each other's `send` /
605            /// `recv` mutations — the producer/consumer-endpoints
606            /// shape. See `$crate::heap_value::ChannelData` for the
607            /// storage shape and the §2.7.20 amendment for the design
608            /// rationale.
609            ///
610            /// Full HeapValue arm (NOT pure-discriminator like FilterExpr
611            /// / SharedCell): Channel values flow through
612            /// `slot.as_heap_value()` for receiver classification at
613            /// method dispatch — same shape as `HashSet` / `Iterator`.
614            Channel(std::sync::Arc<$crate::heap_value::ChannelData>),
615            // ===== Wave 15 W15-priority-queue (ADR-006 §2.7.18 / Q19,
616            // 2026-05-10) =====
617            /// Min-heap-backed PriorityQueue carrier. Mirror of
618            /// `HeapValue::HashSet(Arc<HashSetData>)` with the keys
619            /// buffer carrying i64 priorities instead of `Arc<String>`:
620            /// `Arc<TypedBuffer<i64>>` heap-ordered values (root = min).
621            /// See `$crate::heap_value::PriorityQueueData` for the
622            /// storage shape.
623            ///
624            /// Full HeapValue arm (NOT pure-discriminator like FilterExpr
625            /// / SharedCell): PriorityQueue values flow through
626            /// `as_heap_value()` for method-receiver classification per
627            /// the §2.7.18 amendment.
628            ///
629            /// **i64-priority-only at landing** per the §2.7.18 Q19
630            /// ruling (typed-payload `PriorityQueue<T, K>` with
631            /// key-extractor is a future Phase-2c amendment with
632            /// measurement; the smoke target is exercised on this
633            /// shape).
634            PriorityQueue(std::sync::Arc<$crate::heap_value::PriorityQueueData>),
635            // ===== W15-range (ADR-006 §2.7.23 / Q24, 2026-05-10) =====
636            /// Range value carrier (`Arc<RangeData>`). Built by
637            /// `MakeRange` from the `start..end` / `start..=end` surface
638            /// syntax. Slot bits are `Arc::into_raw(Arc<RangeData>) as
639            /// u64` (typed-Arc shape, mirror of HashMap / HashSet /
640            /// Iterator). Recovery goes through `slot.as_heap_value()`
641            /// → `HeapValue::Range(arc)` for receiver classification at
642            /// method dispatch (`r.contains(x)` / `r.toArray()` /
643            /// `r.iter()`). Same dispatch shape as the FilterExpr §2.7.9
644            /// amendment for refcount discipline (clone_with_kind /
645            /// drop_with_kind retain/release `Arc<RangeData>` directly,
646            /// NOT through `HeapValue`).
647            Range(std::sync::Arc<$crate::heap_value::RangeData>),
648            // ===== Wave 14 W14-variant-codegen (ADR-006 §2.7.17 / Q18,
649            // 2026-05-10) =====
650            /// Result<T, E> carrier (`Arc<ResultData>`). Used by the
651            /// `OkCtor` / `ErrCtor` builtin producers and the
652            /// `op_is_ok` / `op_is_err` / `op_unwrap_ok` /
653            /// `op_unwrap_err` / `op_try_unwrap` discriminators.
654            /// Slot bits are `Arc::into_raw(Arc<ResultData>) as u64`;
655            /// recovery goes through `slot.as_heap_value()` →
656            /// `HeapValue::Result(arc)` per ADR-005 §1
657            /// single-discriminator. The inner `payload: KindedSlot`
658            /// owns one strong-count share for the wrapped value;
659            /// `ResultData::Drop` (auto-derived from `KindedSlot`'s
660            /// explicit Drop) retires the share at refcount=0.
661            Result(std::sync::Arc<$crate::heap_value::ResultData>),
662            /// Option<T> carrier (`Arc<OptionData>`). Used by the
663            /// `SomeCtor` builtin producer and the `op_unwrap_option`
664            /// discriminator (the `None` half is also constructed as
665            /// `OptionData::none()` at compiler emission sites). Same
666            /// kinded-payload discipline as `Result` per §2.7.17.
667            Option(std::sync::Arc<$crate::heap_value::OptionData>),
668            // ===== W17-trait-object-storage (ADR-006 §2.7.24 / Q25.C,
669            // 2026-05-11) =====
670            /// `dyn Trait` carrier (`Arc<TraitObjectStorage>`).
671            /// Re-introduces the bulldozer-deleted `HeapValue::TraitObject`
672            /// arm as a typed-Arc pair — `TraitObjectStorage` holds an
673            /// `Arc<TypedObjectStorage>` data half + an `Arc<VTable>`
674            /// vtable half. Slot bits are
675            /// `Arc::into_raw(Arc<TraitObjectStorage>) as u64`;
676            /// recovery goes through `slot.as_heap_value()` →
677            /// `HeapValue::TraitObject(arc)` per ADR-005 §1
678            /// single-discriminator. The compiler-emission tier
679            /// (W17-trait-object-emission round) populates the slot
680            /// via `OpCode::BoxTraitObject` and dispatches method
681            /// calls via `OpCode::DynMethodCall` against the recovered
682            /// trait-object carrier. See ADR-006 §2.7.24 Q25.C.1
683            /// (universal-dyn auto-boxing), Q25.C.2 (Self-arg runtime
684            /// vtable-identity check), Q25.C.3 (generic-method
685            /// TypeInfo dispatch), Q25.C.5 (`VTableEntry` 6-variant
686            /// shape).
687            ///
688            /// **Wave 2 Round 4 D4 ckpt-final-prime² (2026-05-14): payload
689            /// flipped from `Arc<TraitObjectStorage>` to `TraitObjectPtr`**
690            /// (`#[repr(transparent)]` newtype around
691            /// `*const TraitObjectStorage`) per the §Q25.C.5 amendment +
692            /// Path B ratification. Mirror of the TypedObject flip in the
693            /// same commit — the newtype owns one v2-raw HeapHeader-at-
694            /// offset-0 refcount share; Clone via `v2_retain`, Drop via
695            /// `TraitObjectStorage::release_elem`.
696            TraitObject($crate::heap_value::TraitObjectPtr),
697            // ===== W17-concurrency (ADR-006 §2.7.25, 2026-05-11) =====
698            /// `Mutex<T>` concurrency-primitive carrier
699            /// (`Arc<MutexData>`). The inner `MutexData` wraps a
700            /// `Mutex<MutexInner>` so two `Arc<MutexData>` shares of
701            /// the same mutex observe each other's `set` mutations —
702            /// the same interior-mutability shape as
703            /// `HeapValue::Channel`. Full HeapValue arm — Mutex values
704            /// flow through `slot.as_heap_value()` for receiver
705            /// classification at method dispatch.
706            Mutex(std::sync::Arc<$crate::heap_value::MutexData>),
707            /// `Atomic<i64>` concurrency-primitive carrier
708            /// (`Arc<AtomicData>`). The inner `AtomicData` wraps a
709            /// `std::sync::atomic::AtomicI64` for atomic load / store /
710            /// fetch_add / fetch_sub / compare_exchange. i64-only at
711            /// landing per ADR-006 §2.7.25 — typed-payload `Atomic<T>`
712            /// is a future Phase-2c amendment with measurement.
713            Atomic(std::sync::Arc<$crate::heap_value::AtomicData>),
714            /// `Lazy<T>` initialize-once carrier (`Arc<LazyData>`).
715            /// Wraps an initializer closure and cached value slot.
716            /// Closure-call path is unlocked by W17-make-closure
717            /// (merged at `aa47364`). Full HeapValue arm.
718            Lazy(std::sync::Arc<$crate::heap_value::LazyData>),
719            // ===== W17-comptime-vm-dispatch (ADR-006 §2.7.26, 2026-05-12) =====
720            /// Module-function reference inline-scalar carrier — labels
721            /// a slot whose bits decode to a `module_fn_id: u64` indexing
722            /// `VirtualMachine.module_fn_table`. Inline-scalar payload
723            /// (no `Arc<T>`, no heap state) — same shape as
724            /// `HeapValue::Future(u64)` / `HeapValue::Char(char)`.
725            ///
726            /// Pure-discriminator pattern: in current code ModuleFn
727            /// payloads are emitted directly to the kinded stack /
728            /// TypedObject slot as `module_fn_id as u64` with kind
729            /// `NativeKind::Ptr(HeapKind::ModuleFn)` and never wrapped
730            /// in `HeapValue`. The arm exists to preserve the ADR-005
731            /// §1 / ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry — same
732            /// pattern as `HeapValue::FilterExpr` (§2.7.9) /
733            /// `HeapValue::Reference` (§2.7.13). Calling
734            /// `slot.as_heap_value()` on a ModuleFn-labeled slot is
735            /// undefined behavior; the canonical recovery is reading
736            /// the raw `u64` bits as the `module_fn_id`.
737            ModuleFn(u64),
738            // ===== Round 18 S3 W12-matrix-floatslice-heapkind-exit
739            // (ADR-006 §2.7.22 amendment, 2026-05-13) =====
740            /// Matrix value carrier (`Arc<MatrixData>`). Built by
741            /// `op_new_matrix` from the `matrix(rows, cols, [data...])`
742            /// surface form. In current code Matrix payloads are emitted
743            /// directly to the kinded stack / TypedObject slot as
744            /// `Arc::into_raw(Arc<MatrixData>) as u64` with kind
745            /// `NativeKind::Ptr(HeapKind::Matrix)` and never wrapped in
746            /// `HeapValue`. The arm exists to preserve the ADR-005 §1 /
747            /// ADR-006 §2.3 `HeapKind`↔`HeapValue` symmetry — same
748            /// pattern as `HeapValue::FilterExpr` (§2.7.9) /
749            /// `HeapValue::Reference` (§2.7.13). Calling
750            /// `slot.as_heap_value()` on a Matrix-labeled slot is
751            /// undefined behavior; the canonical recovery is
752            /// `Arc::<MatrixData>::from_raw(bits)`.
753            Matrix(std::sync::Arc<$crate::heap_value::MatrixData>),
754            /// Matrix-projection carrier (`Arc<MatrixSliceData>`). Built
755            /// by `Matrix.row(i)` / `Matrix.col(i)` from a parent matrix.
756            /// `MatrixSliceData { parent: Arc<MatrixData>, offset, len }`
757            /// preserves the aliasing-into-parent semantics from the
758            /// pre-amendment `TypedArrayData::FloatSlice` shape. Same
759            /// typed-Arc pure-discriminator dispatch shape as
760            /// `HeapValue::Matrix`.
761            MatrixSlice(std::sync::Arc<$crate::heap_value::MatrixSliceData>),
762        }
763
764        impl HeapValue {
765            /// Get the kind discriminator for fast dispatch without full pattern matching.
766            #[inline]
767            pub fn kind(&self) -> HeapKind {
768                match self {
769                    HeapValue::String(..) => HeapKind::String,
770                    HeapValue::Decimal(..) => HeapKind::Decimal,
771                    HeapValue::BigInt(..) => HeapKind::BigInt,
772                    HeapValue::Future(..) => HeapKind::Future,
773                    HeapValue::Char(..) => HeapKind::Char,
774                    HeapValue::DataTable(..) => HeapKind::DataTable,
775                    HeapValue::Content(..) => HeapKind::Content,
776                    HeapValue::Instant(..) => HeapKind::Instant,
777                    HeapValue::IoHandle(..) => HeapKind::IoHandle,
778                    HeapValue::NativeScalar(..) => HeapKind::NativeScalar,
779                    HeapValue::NativeView(..) => HeapKind::NativeView,
780                    HeapValue::TypedObject(..) => HeapKind::TypedObject,
781                    HeapValue::ClosureRaw(..) => HeapKind::Closure,
782                    HeapValue::TaskGroup(..) => HeapKind::TaskGroup,
783                    // V3-S5 ckpt-4: `HeapValue::TypedArray(..)` kind arm
784                    // deleted in lockstep with the variant + the
785                    // TypedArrayData enum (ckpt-1) + wrapper layer (ckpt-4).
786                    // `HeapKind::TypedArray = 8` ordinal is vacated (see
787                    // ordinal table above) but the identifier stays until
788                    // ckpt-5 4-table-lockstep deletion.
789                    HeapValue::Temporal(..) => HeapKind::Temporal,
790                    HeapValue::TableView(..) => HeapKind::TableView,
791                    HeapValue::HashMap(..) => HeapKind::HashMap,
792                    HeapValue::HashSet(..) => HeapKind::HashSet,
793                    HeapValue::FilterExpr(..) => HeapKind::FilterExpr,
794                    HeapValue::Reference(..) => HeapKind::Reference,
795                    HeapValue::Iterator(..) => HeapKind::Iterator,
796                    HeapValue::Deque(..) => HeapKind::Deque,
797                    HeapValue::Channel(..) => HeapKind::Channel,
798                    HeapValue::PriorityQueue(..) => HeapKind::PriorityQueue,
799                    HeapValue::Range(..) => HeapKind::Range,
800                    HeapValue::Result(..) => HeapKind::Result,
801                    HeapValue::Option(..) => HeapKind::Option,
802                    HeapValue::TraitObject(..) => HeapKind::TraitObject,
803                    HeapValue::Mutex(..) => HeapKind::Mutex,
804                    HeapValue::Atomic(..) => HeapKind::Atomic,
805                    HeapValue::Lazy(..) => HeapKind::Lazy,
806                    HeapValue::ModuleFn(..) => HeapKind::ModuleFn,
807                    HeapValue::Matrix(..) => HeapKind::Matrix,
808                    HeapValue::MatrixSlice(..) => HeapKind::MatrixSlice,
809                }
810            }
811
812            /// Check if this heap value is truthy.
813            #[inline]
814            pub fn is_truthy(&self) -> bool {
815                match self {
816                    HeapValue::String(_v) => !_v.is_empty(),
817                    HeapValue::Decimal(_v) => !_v.is_zero(),
818                    HeapValue::BigInt(_v) => **_v != 0,
819                    HeapValue::Future(_) => true,
820                    HeapValue::Char(_) => true,
821                    HeapValue::DataTable(_v) => _v.row_count() > 0,
822                    HeapValue::Content(_) => true,
823                    HeapValue::Instant(_) => true,
824                    HeapValue::IoHandle(_v) => _v.is_open(),
825                    HeapValue::NativeScalar(_v) => _v.is_truthy(),
826                    HeapValue::NativeView(_v) => _v.ptr != 0,
827                    HeapValue::TypedObject(s) => !s.slots.is_empty(),
828                    HeapValue::ClosureRaw(..) => true,
829                    HeapValue::TaskGroup(..) => true,
830                    // V3-S5 ckpt-4: `HeapValue::TypedArray(ta) => ta.is_truthy()`
831                    // arm deleted in lockstep with the variant + the
832                    // `TypedArrayData::is_truthy` impl (ckpt-1 wholesale deletion).
833                    HeapValue::Temporal(td) => td.is_truthy(),
834                    HeapValue::TableView(tv) => tv.is_truthy(),
835                    HeapValue::HashMap(d) => !d.is_empty(),
836                    HeapValue::HashSet(d) => !d.is_empty(),
837                    // Filter-expression trees are always truthy when present.
838                    HeapValue::FilterExpr(_) => true,
839                    // Reference values are always truthy when present
840                    // (a live ref points at a reachable place).
841                    HeapValue::Reference(_) => true,
842                    // Iterator values are always truthy when present
843                    // (a live iterator is a usable pipeline value, even
844                    // if its terminal evaluation will yield zero
845                    // elements after filter / take 0 etc.).
846                    HeapValue::Iterator(_) => true,
847                    // Wave 15 W15-deque (ADR-006 §2.7.19 / Q20):
848                    // truthy iff the deque has at least one element.
849                    HeapValue::Deque(d) => !d.is_empty(),
850                    // Channel values are always truthy when present
851                    // (a live channel is a usable endpoint regardless of
852                    // queued-element count or closed state).
853                    HeapValue::Channel(_) => true,
854                    // Wave 15 W15-priority-queue (ADR-006 §2.7.18 / Q19,
855                    // 2026-05-10): empty PQ is falsy, non-empty is
856                    // truthy — mirror of the HashSet / HashMap shape.
857                    HeapValue::PriorityQueue(d) => !d.is_empty(),
858                    // Empty range (zero elements) is falsy; non-empty is
859                    // truthy. Mirrors the HashSet/HashMap "empty is
860                    // falsy" pattern at §2.7.15. Cheap O(1) check via
861                    // `RangeData::is_empty()`.
862                    HeapValue::Range(r) => !r.is_empty(),
863                    // Result and Option are always truthy when present
864                    // (a wrapper's variant tag is a runtime contract;
865                    // truthiness reflects "carrier exists" not the
866                    // inner success/none state). Inner-aware boolean
867                    // tests go through `op_is_ok` / `op_is_err`.
868                    HeapValue::Result(_) => true,
869                    HeapValue::Option(_) => true,
870                    // W17-trait-object-storage (ADR-006 §2.7.24 / Q25.C,
871                    // 2026-05-11): a `dyn Trait` carrier is always
872                    // truthy when present — a boxed trait object is a
873                    // live receiver regardless of its inner value.
874                    // Same shape as Reference / Iterator / Channel.
875                    HeapValue::TraitObject(_) => true,
876                    // W17-concurrency (ADR-006 §2.7.25, 2026-05-11):
877                    // concurrency primitives are always truthy when
878                    // present — a live mutex/atomic/lazy is a usable
879                    // synchronisation handle regardless of inner state.
880                    // Same shape as Channel / Iterator / Reference.
881                    HeapValue::Mutex(_) => true,
882                    HeapValue::Atomic(_) => true,
883                    HeapValue::Lazy(_) => true,
884                    // ModuleFn references are always truthy when present
885                    // (a live module-fn-id is a usable callable handle).
886                    HeapValue::ModuleFn(_) => true,
887                    // ADR-006 §2.7.22 amendment (Round 18 S3, 2026-05-13):
888                    // truthy iff the underlying flat buffer / projection
889                    // length is non-empty, mirroring the pre-amendment
890                    // `TypedArrayData::Matrix` / `FloatSlice` is_truthy
891                    // shape.
892                    HeapValue::Matrix(m) => m.data.len() > 0,
893                    HeapValue::MatrixSlice(s) => s.len > 0,
894                }
895            }
896
897            /// Get the type name for this heap value.
898            #[inline]
899            pub fn type_name(&self) -> &'static str {
900                match self {
901                    HeapValue::String(_) => "string",
902                    HeapValue::Decimal(_) => "decimal",
903                    HeapValue::BigInt(_) => "int",
904                    HeapValue::Future(_) => "future",
905                    HeapValue::Char(_) => "char",
906                    HeapValue::DataTable(_) => "datatable",
907                    HeapValue::Content(_) => "content",
908                    HeapValue::Instant(_) => "instant",
909                    HeapValue::IoHandle(_) => "io_handle",
910                    HeapValue::NativeScalar(v) => v.type_name(),
911                    HeapValue::NativeView(v) => {
912                        if v.mutable {
913                            "cmut"
914                        } else {
915                            "cview"
916                        }
917                    }
918                    HeapValue::TypedObject(..) => "object",
919                    HeapValue::ClosureRaw(..) => "closure",
920                    HeapValue::TaskGroup(..) => "task_group",
921                    // V3-S5 ckpt-4: `HeapValue::TypedArray(ta) => ta.type_name()`
922                    // arm deleted in lockstep with the variant + the
923                    // `TypedArrayData::type_name` impl (ckpt-1 wholesale deletion).
924                    HeapValue::Temporal(td) => td.type_name(),
925                    HeapValue::TableView(tv) => tv.type_name(),
926                    HeapValue::HashMap(_) => "hashmap",
927                    HeapValue::HashSet(_) => "hashset",
928                    HeapValue::FilterExpr(_) => "filter_expr",
929                    HeapValue::Reference(_) => "ref",
930                    HeapValue::Iterator(_) => "iterator",
931                    HeapValue::Deque(_) => "deque",
932                    HeapValue::Channel(_) => "channel",
933                    HeapValue::PriorityQueue(_) => "priority_queue",
934                    HeapValue::Range(_) => "range",
935                    HeapValue::Result(_) => "result",
936                    HeapValue::Option(_) => "option",
937                    HeapValue::TraitObject(_) => "trait_object",
938                    HeapValue::Mutex(_) => "mutex",
939                    HeapValue::Atomic(_) => "atomic",
940                    HeapValue::Lazy(_) => "lazy",
941                    HeapValue::ModuleFn(_) => "module_fn",
942                    // ADR-006 §2.7.22 amendment (Round 18 S3, 2026-05-13).
943                    HeapValue::Matrix(_) => "matrix",
944                    HeapValue::MatrixSlice(_) => "matrix_slice",
945                }
946            }
947        }
948    };
949}