Repository navigation
Conversation
List operations could lose owned handles, copy linear elements, and disagree across their declared signatures, constant folding, and LLVM results. Make lists always linear, return the list alongside `get`'s optional copied element, and require copyable elements for `get`. Add `new` and `discard_empty`; empty disposal accepts arbitrary element types and panics if any elements remain. Allow insertion at the length and use an empty success row, while failed mutations preserve the list and return the input element. Implement LLVM list operations with an owned byte buffer and checked capacity growth. All handle and buffer allocations and matching frees use customizable codegen hooks, including constant construction and allocate-copy-free growth. Nonempty disposal and allocation/capacity failures use the selected `PreludeCodegen`. Reconcile the Rust and Python types, generated declarations, specification, and constant folding, and encode Python list constants with the Rust-compatible tuple payload. BREAKING CHANGE: `collections.list` is now version `0.2.0`. `List<T>` is always linear and `get` returns `(List<T>, Option<T>)` for copyable elements. Thread returned handles through list operations and consume emptied handles with `discard_empty`. Successful `insert` carries an empty row.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3307 +/- ##
==========================================
+ Coverage 82.05% 82.33% +0.28%
==========================================
Files 245 245
Lines 47553 48509 +956
Branches 41144 42088 +944
==========================================
+ Hits 39020 39941 +921
+ Misses 6629 6605 -24
- Partials 1904 1963 +59
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Inkwell 0.9 requires copied memory-buffer input to end with a NUL byte. Terminate the embedded list IR before parsing it in both codegen and the direct runtime exercise, preserving compatibility with both supported Inkwell versions.
There was a problem hiding this comment.
🟡 Changes recommended
Constant folding can create invalid polymorphic constants, while LLVM ABI assumptions break supported custom codegen configurations.
3 open findings
What changed in this PR
Updates linear list ownership semantics and adds an owned-buffer LLVM implementation.
Changes:
- Makes lists linear and reconciles operation signatures, folding, serialization, and documentation.
- Adds
new,discard_empty, append insertion, and corrected mutation results. - Implements LLVM list allocation, growth, disposal, panic hooks, and execution tests.
| File | Description |
|---|---|
specification/stdlib.md |
Documents revised list semantics. |
resources/std_extensions/collections/list.json |
Updates generated extension schema. |
hugr-py/tests/test_val.py |
Tests list constant serialization. |
hugr-py/tests/test_tys.py |
Tests list bounds and signatures. |
hugr-py/src/hugr/std/collections/list.py |
Makes lists linear and fixes serialization. |
hugr-py/src/hugr/std/_json_defs/collections/list.json |
Updates Python extension definitions. |
hugr-llvm/src/extension/collections/list.rs |
Implements LLVM lowering and tests. |
hugr-llvm/src/extension/collections/list_runtime.ll |
Adds the byte-buffer runtime. |
hugr-llvm/src/emit/func.rs |
Extracts function-definition support. |
hugr-core/src/std_extensions/collections/list/list_fold.rs |
Reconciles constant folding. |
hugr-core/src/std_extensions/collections/list.rs |
Revises core list API and types. |
hugr-core/src/extension/resolution/test.rs |
Consumes linear constants in tests. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__set@pre-mem2reg@llvm21.snap |
Updates set lowering snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__set@llvm21.snap |
Updates optimized set snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__pop@pre-mem2reg@llvm21.snap |
Updates pop lowering snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__pop@llvm21.snap |
Updates optimized pop snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__new@pre-mem2reg@llvm21.snap |
Adds new-list snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__new@llvm21.snap |
Adds optimized new-list snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__get@pre-mem2reg@llvm21.snap |
Updates get lowering snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__get@llvm21.snap |
Updates optimized get snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__discard_empty@pre-mem2reg@llvm21.snap |
Adds disposal snapshot. |
hugr-llvm/src/extension/collections/snapshots/hugr_llvm__extension__collections__list__test__discard_empty@llvm21.snap |
Adds optimized disposal snapshot. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let [ty] = args else { return None }; | ||
| if !inputs.is_empty() { | ||
| return None; | ||
| } |
There was a problem hiding this comment.
Fixed in ff2c8b2. The new-list folder validates the element type with an empty variable scope before constructing a constant. A regression covers free variables directly and inside tuple/list types for both bounds, while concrete copyable and linear element types still fold. The regression failed before the fix; the full core suite now passes.
| &[ | ||
| iwc.i64_type().const_zero().into(), | ||
| elem_ty.size_of().unwrap().into(), | ||
| iwc.i64_type().const_int(1, false).into(), |
There was a problem hiding this comment.
Fixed in ff2c8b2. Both dynamic new and constant construction now pass elem_ty.get_alignment(), preserving the constructor ABI while supplying target-derived alignment. An external-runtime execution regression observes this argument for usize, qubit, and unit elements in both construction paths; all six cases pass. The embedded byte-copy runtime remains independent of buffer element alignment.
| define i1 @__rt__list__get(ptr %list, i64 %idx, ptr %out) { | ||
| entry: | ||
| %len = call i64 @__rt__list__length(ptr %list) |
There was a problem hiding this comment.
Fixed in ff2c8b2. Operation boundaries now convert the registered prelude usize to/from the fixed i64 runtime ABI. Wider indices remain out of bounds instead of wrapping, and unrepresentable narrow length results panic through the selected PreludeCodegen. Execution regressions cover the operation matrix and constant lists with i32/i64/i128 preludes, indices above 64 bits, and the custom panic for length overflow. The full LLVM suite passes on both current dependencies and Rust 1.91/minimum dependencies.
Skip empty-list constant folding when the element type contains free variables, since constants have no enclosing type-variable scope. Pass the element's target alignment consistently for dynamic and constant constructors. Convert configured prelude indices and lengths at the fixed-width list runtime boundary. Preserve out-of-bounds wide indices and panic through the selected PreludeCodegen when a length cannot be represented by the configured usize type.

List operations could lose owned handles, copy linear elements, and disagree across their declared signatures, constant folding, and LLVM results. Make lists always linear, return the list alongside
get's optional copied element, and require copyable elements forget. Addnewanddiscard_empty; empty disposal accepts arbitrary element types and panics if any elements remain. Allow insertion at the length and use an empty success row, while failed mutations preserve the list and return the input element.Implement LLVM list operations with an owned byte buffer and checked capacity growth. All handle and buffer allocations and matching frees use customizable codegen hooks, including constant construction and allocate-copy-free growth. Nonempty disposal and allocation/capacity failures use the selected
PreludeCodegen. Reconcile the Rust and Python types, generated declarations, specification, and constant folding, and encode Python list constants with the Rust-compatible tuple payload.BREAKING CHANGE:
collections.listis now version0.2.0.List<T>is always linear andgetreturns(List<T>, Option<T>)for copyable elements. Thread returned handles through list operations and consume emptied handles withdiscard_empty. Successfulinsertcarries an empty row.