Skip to content

compile-match-tree: variable bindings in compound patterns alias outer-param storage in recursive bodies #18

Description

@hierophantos

Summary

In a multi-clause defn whose pattern dispatch decomposes a compound parameter (e.g. cons r rest) and whose body recurses on a sub-binding (e.g. [recurse rest]), compile-match-tree lowers variable bindings to positional let v := __cons_N references that point at outer-parameter storage already overwritten by a later dispatch column. The recursive call receives a corrupted value and produces wrong results silently.

Reproducer

spec sum-rows [List Nat] -> Nat
defn sum-rows
  | nil            -> 0N
  | cons r nil     -> r
  | cons r rest    -> [+ r [sum-rows rest]]
[sum-rows '[1N 2N 3N]]

Expected: 6N
Actual: incorrect value (rest is corrupted; recursion produces wrong result)

The bug reproduces on current main using the bracketed form [[cons r rest]] which compiles to the same internal AST. PR #16 (auto-pack of bare-token compound patterns) makes the bug easier to hit at the syntax level but does not introduce it — the bug pre-exists.

Diagnosis (from PR #16's commit message and disclosure)

Variable patterns named in a sub-position get bound via let v := __cons_1, referring to a param that's been destructured by a later dispatch column.

Bug location: compile-match-tree. The variable lowering emits let bindings against positional storage names (__cons_0, __cons_1) that aren't preserved across dispatch columns — when a later column inspects the same parameter slot, the storage is overwritten and let v := __cons_1 reads the new contents.

What works (covered by PR #16's tests)

  • [sum-rows '[]] — first clause matches, no compound dispatch
  • [sum-rows '[42N]] — second clause matches (cons r nil), r extracted directly, no recursive descent into the buggy slice

What's broken

  • Any input ≥ 2 elements that traverses a recursive compound clause
  • The general idiom: structural-decomposition pattern + recursive call on a sub-bound variable
  • Likely affects List traversal (cons), Tree traversal, Pair destructuring — a load-bearing functional-programming pattern

Scope

Provenance

Severity

Medium-high. Silent wrong results (not an error) on a load-bearing functional-programming idiom. Especially dangerous because users writing standard recursive structural code over Lists or Trees can hit it without knowing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions