Skip to content

Conversation

@lukewilliamboswell
Copy link
Collaborator

@lukewilliamboswell lukewilliamboswell commented Jan 31, 2026

Summary

Fix segfault (issue #9113) when pattern matching on recursive opaque types extracted from lists. This PR addresses two related issues:

1. List element re-boxing (original fix)

When a recursive opaque type (like Element) is stored in a list, elements are auto-boxed for uniform size. When these elements are later used as tag union payloads, the code now correctly re-boxes them to match the expected layout.

2. Incorrect auto-boxing in record_collect (new fix)

The record_collect continuation was incorrectly auto-boxing fields based on whether the field's type is self-recursive. This caused layout mismatches when a separate recursive type (like NodeA) was used in a different type's record field (like NodeB's FoldB payload).

The fix removes this incorrect auto-boxing. The type-based layout is the source of truth:

  • When a type references itself (Type := [Node({ child: Type })]), the layout system correctly creates Box(Type) during layout computation.
  • When a separate recursive type is used ({ event: NodeA }), it should NOT be boxed because NodeA is already a complete type.

Changes

  1. List re-boxing in tag_collect: When storing a list as a tag variant payload, if the expected element layout is box but the actual list has non-boxed elements, re-box each element
  2. Remove incorrect auto-boxing in record_collect: Removed the logic that auto-boxed all self-recursive tag unions in record fields, which caused layout mismatches with the type-based layout
  3. Dynamic discriminant offset: Use dynamic computation instead of stored value for recursive types

Test plan

  • Added regression test test/fx/issue9113_simple.roc (tests list re-boxing)
  • Added regression test test/fx/list_opaque_pattern_match_bug.roc (tests nested opaque types)
  • All unit tests pass
  • zig build minici passes

Fixes #9113

🤖 Generated with Claude Code

@lukewilliamboswell lukewilliamboswell marked this pull request as ready for review January 31, 2026 01:12
…9113)

This PR fixes two related issues:

1. **List element re-boxing (original fix)**: When a recursive opaque type
   (like `Element`) is stored in a list, elements are auto-boxed for uniform
   size. When these elements are later used as tag union payloads, the code
   now correctly re-boxes them to match the expected layout.

2. **Incorrect auto-boxing in record_collect (new fix)**: The `record_collect`
   continuation was incorrectly auto-boxing fields based on whether the
   field's type is self-recursive. This caused layout mismatches when a
   separate recursive type (like `NodeA`) was used in a different type's
   record field (like `NodeB`'s `FoldB` payload).

   The fix removes this incorrect auto-boxing. The type-based layout is the
   source of truth:
   - When a type references itself (`Type := [Node({ child: Type })]`), the
     layout system correctly creates `Box(Type)` during computation.
   - When a separate recursive type is used (`{ event: NodeA }`), it should
     NOT be boxed because `NodeA` is already a complete type.

Test cases added:
- `issue9113_simple.roc`: Tests the original list re-boxing fix
- `list_opaque_pattern_match_bug.roc`: Tests nested opaque types in lists

Co-Authored-By: Claude Opus 4.5 <[email protected]>
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.

Pattern matching crashes on opaque type variants retrieved from lists

2 participants