Skip to content

feat(codegen): emit typed WIT list from Array data types (#345)#346

Merged
avrabe merged 3 commits into
mainfrom
feat/wit-array-list-345
Jul 23, 2026
Merged

feat(codegen): emit typed WIT list from Array data types (#345)#346
avrabe merged 3 commits into
mainfrom
feat/wit-array-list-345

Conversation

@avrabe

@avrabe avrabe commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes the #345 gap: spar codegen --format wit mapped every AADL data type with Data_Representation => Array to an opaque type x = list<u8>, dropping the element type and dimension — so an inter-core WIT contract could only say list, not the real payload (the jess NavState 16 × f32).

This teaches codegen to emit a typed WIT list from a Data Modeling Annex Array data type.

What changed

  • spar-hir-def (resolver.rs) — new DataShape::Array { element, len }. resolve_data_shape recognizes Data_Representation => Array, resolves the Base_Type classifier to the element shape (recursively, reusing the existing scalar/record resolution), and reads the first Dimension as the length. Both the maintainer's list-wrapped property syntax (Base_Type => (classifier(Pkg::T)), Dimension => (16)) and the bare forms are accepted.
  • spar-codegen (wit_gen.rs) — a fixed Dimension emits a bounded fixed-size list<T, N> (no cabi_realloc, consistent with the RECORDS‑002 no_alloc discipline where only unbounded list/string force dynamic allocation); no Dimension emits list<T>. The element resolves through a shared shape_wit_type helper, so an array-of-record and an array-typed record field both work.
  • spar-codegen (rust_gen.rs) — the Rust port type mirrors wit-bindgen's lowering: list<T, N>[T; N], list<T>Vec<T>.

Honest scoping / no regression

An Array whose Base_Type is absent or resolves to an unsized/unresolvable element (e.g. the standard Base_Types::Float, which carries no Data_Size) is not fabricated: array_of returns None, so a top-level array port gracefully keeps the legacy list<u8> (no regression, no hard error), and an array-typed record field takes the record no_alloc hard-error path — exactly as an opaque field would.

Not claimed here: list byte-layout ↔ canonical-ABI equivalence (that's #327's ordeal work); multi-dimensional arrays use only the first Dimension; no compiled-crate oracle for array ports on the Rust side.

Oracles (executed unit tests, spar-codegen/src/wit_gen.rs)

Each asserts the emitted WIT parses + resolves under wit_parser (a real fixed-size-list bind, not a string match).

cargo test -p spar-codegen --lib → 56 passed. cargo test -p spar-hir-def --lib → 471 passed. cargo fmt --check clean; cargo clippy on both crates clean. An independent clean-room agent re-derived each claim against its own fixtures.

Tracked as REQ-CODEGEN-WIT-ARRAY-001.

Note: case (b) of #345 (a data implementation with subcomponents) already works today when the port references the implementation classifier (VehicleState.nav) rather than the bare data type — details in the issue reply.

🤖 Generated with Claude Code


Generated by Claude Code

An AADL `data` type with `Data_Representation => Array` previously
degraded to an opaque `type x = list<u8>` in `spar codegen --format wit`,
dropping the element type and dimension so an inter-core contract could
only say `list`, not the real payload.

Add a `DataShape::Array { element, len }` variant. `resolve_data_shape`
now recognizes the Data Modeling Annex `Array` representation, resolves
the `Base_Type` classifier to the element shape (recursively, reusing the
scalar/record resolution) and reads the first `Dimension` as the length.
Both the list-wrapped property syntax (`Base_Type => (classifier(T))`,
`Dimension => (16)`) and the bare forms are accepted.

Codegen emits a bounded fixed-size `list<T, N>` when the dimension is
known (no `cabi_realloc`, consistent with the no_alloc discipline) and an
unbounded `list<T>` otherwise. An Array whose `Base_Type` is absent or
resolves to an unsized/unresolvable element is NOT fabricated: a top-level
port gracefully keeps the legacy opaque `list<u8>`; an array-typed record
field takes the record no_alloc hard-error path. The Rust port type
mirrors wit-bindgen's lowering (`list<T, N>` -> `[T; N]`, `list<T>` ->
`Vec<T>`).

Oracles (spar-codegen/src/wit_gen.rs): the #345 NavState case yields
`type vehicle-state = list<f32, 16>;`; unbounded -> `list<f32>`; no
Base_Type and unsized-element both stay `list<u8>`; an array-typed record
field -> `nav: list<f32, 16>`. Each asserts the emitted WIT parses and
resolves under wit-parser. REQ-CODEGEN-WIT-ARRAY-001.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

avrabe commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

CI blocked by self-hosted runner disk exhaustion (infra, not this diff)

Three required checks failed — Proptest (extended), Fuzz smoke, Bench compile smoke — all with the same root cause: the self-hosted runners are out of disk.

  • Bench compile smoke (runner5): error: failed to write to '.../target/release/deps/rmetaNfJLue/full.rmeta': No space left on device (os error 28)
  • Proptest (extended) (runner11): ld terminated with signal 7 [Bus error], core dumped while linking spar-mcp (SIGBUS = the linker's mmap'd output hit a full disk)
  • Both post-job hooks report disk: 100% used (threshold 70%), and the cleanup step could not reclaim space (cleanup done: disk 100% → 100%).

This is not related to this PR's change: it's isolated to spar-mcp linking / lsp-types codegen (crates this diff doesn't touch), and spar-codegen / spar-hir-def (the crates I changed) compiled cleanly earlier in the same logs. Locally: spar-codegen 56/56, spar-hir-def 471/471, fmt + clippy clean.

Two runners (runner5, runner11) are both at 100% — this looks fleet-wide, which likely also explains why the main v0.32.0 CI run has been stuck queued for hours.

Action needed (runner admin): reclaim disk on the self-hosted runner fleet (prune target/, sccache, and ~/.cargo/registry/cache — the current post-job hook isn't freeing enough). The required checks can't go green until then. I don't have permission to re-run failed jobs (rerun-failed-jobs → 403), and a re-trigger won't help while the runners are full. I'll re-verify and drive this to merge once the disks are back under threshold — nothing to change on the branch itself.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown

Rivet verification gate

20/20 passed

count
Passed 20
Failed 0
Skipped (no steps) 0

Filter: (and (= type "feature") (or (has-tag "v093") (has-tag "v0100")))

Failed artifacts

(none)

Updated automatically by tools/post_verification_comment.py. Source of truth: artifacts/verification.yaml.

No code change. The prior run's Proptest/Fuzz/Bench-compile jobs failed
only because the self-hosted runners were at 100% disk (ENOSPC / linker
SIGBUS on unrelated crates); those jobs are terminal on the old commit
and cannot re-run via the API here. The runner fleet has since recovered
(the heavy Test + Mutation jobs are building the workspace again), so this
empty commit re-triggers a clean CI run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.57995% with 20 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/spar-codegen/src/wit_gen.rs 95.41% 11 Missing ⚠️
crates/spar-hir-def/src/resolver.rs 85.24% 9 Missing ⚠️

📢 Thoughts on this report? Let us know!

Close the rust_gen coverage gap codecov flagged on the array change: add
unit tests for `data_shape_to_rust_type` on `DataShape::Array` (fixed
`[T; N]`, unbounded `Vec<T>`, array-of-record `[crate::types::X; N]`, and
nested `[[f32; 3]; 2]`), and for the array-element recursion in
`flatten_record_rust` (a record field of array-of-record still emits the
inner struct, inner-first). No behavior change. REQ-CODEGEN-WIT-ARRAY-001.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@avrabe
avrabe merged commit b39068e into main Jul 23, 2026
20 checks passed
@avrabe
avrabe deleted the feat/wit-array-list-345 branch July 23, 2026 15:58
avrabe added a commit that referenced this pull request Jul 23, 2026
Version 0.32.0 -> 0.33.0 (Cargo.toml + Cargo.lock + vscode-spar). Promote
REQ-CODEGEN-WIT-ARRAY-001 to verified (release v0.33.0). Releases the typed
WIT list from Array data types (#345 / #346).
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.

2 participants