list and variant sync #438
No reviewers
Labels
No labels
bug
dependencies
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
refactor
rust
technical-debt
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-seq!438
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "list-v"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
New runtime functions
Compiler wiring
Tests
Code Review: list and variant sync (#438)
Overview
This PR adds
list.first,list.last, andvariant.firstconvenience accessors to the runtime and wires them all the way through the compiler (builtins, codegen, error-flag lint, lints.toml). The design is consistent with existing ops and the test coverage is solid.Issues
Bug / Naming Inconsistency — panic messages in
patch_seq_variant_firstcrates/runtime/src/variant_ops/modify.rsBoth panic messages use a dash where the rest of the codebase uses a dot:
The existing
variant_last(and all other ops in this file) use the dot form ("variant.last: ..."). These messages surface in runtime error output, so the wrong prefix makes them harder to grep and confusing to users.Code Duplication —
patch_seq_list_firstandpatch_seq_list_lastcrates/runtime/src/list_ops/access.rsThe two functions are ~85 lines of near-identical code differing only in the index used (
fields[0]vsfields.last().unwrap()). A small private helper would remove the duplication without touching the publicextern "C"surface — the only difference between the two call sites is the closure passed to retrieve the element. This matches the refactoring pattern already used elsewhere in the crate.Suggestions
Missing test:
variant.firstempty-fields pathcrates/runtime/src/variant_ops/tests.rsThe panic on an empty variant is documented but not exercised. A
#[test] #[should_panic]case would lock in the contract and prevent accidental softening of the panic in a future refactor. It would also serve as a regression guard for the panic-message fix noted above.Empty-path placeholder is unasserted in unit tests
crates/runtime/src/list_ops/tests.rstest_list_first_empty_is_failure_tupleandtest_list_last_empty_is_failure_tuplepop the placeholder as_placeholderwithout asserting its value. Since the placeholder (Int 0) is part of the documented public contract, asserting it would make the tests self-describing and prevent silent contract drift.What is Good
(value Bool)shape forlist.first/list.lastis consistent withlist.get— the same error-flag lint infrastructure covers all three with no special-casing needed.lints.tomlfollow the established pattern exactly.variant.first/variant.lastasymmetry (panic vs. soft-failure) is documented clearly in both the Rust doc-comment and the PR description.Summary
One real bug (panic message typo:
variant-firstshould bevariant.first) and one worthwhile refactor (extract the shared list-endpoint helper) before merge. Everything else is style/hardening. The feature itself is correct and well-integrated.Code Review — PR #438: list and variant sync
Overview
This PR adds
list.first/list.lastconvenience accessors (returning a(value Bool)error-flag tuple) andvariant.first(panicking on fieldless variants, mirroringvariant.last). The compiler wiring, lint rules, and test coverage are all thorough. The changes are well-scoped and follow established patterns in the codebase.Code Quality & Style
Positives:
list_endpointhelper cleanly factors out the shared logic betweenlist.firstandlist.last. Using a plainfnpointer instead of a generic/closure to keep FFI wrappers trivial is a good call and the comment explains why."variant-tag:"→"variant.tag:") acrossaccess.rs,make.rs, andmodify.rsare a nice consistency cleanup bundled in sensibly.unsafe {}block insideunsafe fn list_endpointis correct for edition 2024 (unsafe_op_in_unsafe_fnis deny-by-default).unchecked-list-first/unchecked-list-lastcorrectly mirror the existinglist.get droppattern.Minor nit — alignment inconsistency in
builtins/list.rs:The trailing alignment space on
list.lastis inconsistent withlist.firstdirectly above it. Either align both or neither.Potential Issues
1. Asymmetric error semantics between
list.*andvariant.*— documented but worth calling outlist.first/list.lastreturn(value false)on an empty list.variant.first/variant.lastpanic on a fieldless variant. The PR description acknowledges this ("same convention as variant.last"), and the intent is sound — variants are expected to have statically-known structure. However, this asymmetry can surprise callers who assume all*.first/*.lastoperations behave the same way. A one-liner in thevariant.firstdoc comment explicitly noting "unlike list.first, this panics on an empty variant" would help.2. Wrong-type recovery path in
list_endpointpushes a failure tuple despite callingset_runtime_errorOn a type mismatch, the function both records the error and pushes
(Int 0, false). Thefalseflag means Seq code checking the Bool will see a failure, which is reasonable. But there's no unit test exercising this path — a test pushing a non-Variant (e.g.,Value::Int(99)) throughlist_firstand asserting(Int 0, false)would pin the contract for this edge case.3.
list_endpoint—fields[0].clone()is guarded but isolatedThe
is_empty()check before callingpickmakesfields[0]safe. However, thepickcallback is a free function pointer the callers supply; if a future caller passed a closure that index intofieldsdifferently, there'd be no compile-time guard. The current callers are trivial, so this is a very minor design note rather than a real bug.Test Coverage
list.first— non-emptylist.first— singletonlist.last)list.first— empty → failure tuplelist.last— non-emptylist.last— singletonlist.last— empty → failure tuplelist.first/last— wrong type (non-Variant)variant.first— non-emptyvariant.first— singletonvariant.first— fieldless (panic)The one gap worth filling (non-blocking) is a unit test for the wrong-type path in
list_endpoint. The fieldless-variant panic test omission is clearly documented and the reasoning (process-abort acrossextern "C"in edition 2024) is correct.Summary
This is a clean, well-tested addition. The two things worth addressing before merge:
list.lastinbuiltins/list.rs.variant.first's doc comment that it panics on a fieldless variant (unlikelist.first), to make the asymmetry explicit at the call site.list_endpoint.Everything else looks correct and consistent with existing conventions.