Regression: union variants with fields crash at runtime (local main branch) #376
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#376
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Summary
Building
seqcfrom the localmainbranch (post-v4.2.1 tagged-ptr/40-bit removal work) produces a compiler that generates broken code for all union variants with fields. The published crates.io v4.2.1 is unaffected — this is a regression onmainthat must be fixed before the next crates.io publish.Discovered while debugging seq-lisp test failures.
What's broken
Three distinct failures, all related to variant field handling:
1.
Make-*constructors with fields panicThe discriminant values (e.g.
4310895856,4322305760) look like raw pointer values being misinterpreted as discriminant tags — suggests the new tagged-pointer representation is not being decoded correctly by the old variant construction path.2. Generated field accessors panic
at
crates/runtime/src/variant_ops.rs:126:183.
is-*?predicates return wrong resultsOutput:
not red— the predicate fails to recognize a value it just constructed.What still works
Make-Red,Make-Nothing— no crashmatchon nullary variants: pattern matching dispatches correctlyRoot cause (likely)
The v4.1.0 "tagged-ptr default" and v4.2.0 "remove 40-bit support" changes altered the variant memory layout. It appears that:
matchwas updated to use the new representationMake-*(with fields),is-*?, and generated field accessors (Variant-field,variant.field-at) were not fully updatedHow we found it
seq-lisp's first Seq unit test (
test_error_handling) crashed immediately on"(car)" tokenize— the tokenizer usesTokState,TokPos, andTokAccumunion types heavily. The crash traced to_patch_seq_variant_field_atinside_seq_tokenize_loop.Minimal repro narrowed it down to any union variant with at least one field.
How to reproduce
Suggested fix
dup+ predicate). The current test suite apparently doesn't cover this — a single-fieldMake-*/ accessor round-trip test would have caught this immediately.Make-*,is-*?, generated accessors, andvariant.field-atall use the same tagged-pointer representation thatmatchuses.Environment
path+file:///...patch-seq/crates/compiler)@navicore-bot please take a look at this issue
Investigation Results (Rocky Linux 9.7, x86_64, rustc 1.94.0)
After a clean rebuild from the latest
main(commitf667acc), I cannot reproduce this issue. All three failure scenarios from the report now work correctly:1.
Make-*constructors with fields ✅Output:
42(expected)2.
is-*?predicates ✅Output:
is red(expected)3. Multi-field variant access ✅
Output:
10\n20(expected)Full test suite
Likely root cause
The original crash referenced
crates/core/src/stack_old.rs:219:18— a file that no longer exists onmain(removed in the 40-bit cleanup). This strongly suggests the crash was caused by a stale embedded runtime: the compiler binary had the old 40-bit runtime.afile baked in, while the rest of the compiler was updated for the new tagged-ptr layout.A
cargo clean && cargo build --releaseshould resolve this. The build script (crates/compiler/build.rs) embedslibseq_runtime.aat compile time viainclude_bytes!, so an incremental build can pick up the old runtime if only the compiler crate changed.Recommendation
This may be worth adding a safeguard for — e.g., embedding a version hash in the runtime
.aand checking it at load time, or having the build script always rebuild the runtime when the compiler version changes. But functionally, a clean build fixes the issue.I've reinstalled from main and the regression went away. Must have been a partial install or an install of an abandoned change that was reverted but no new "just install" run.