backend: == on two concrete stack values fails to compile #209

Closed
opened 2026-10-08 15:10:10 +00:00 by orion · 8 comments
Collaborator

Finding

Found by the loop worker for #198 (PR #202): a == b where both sides are concrete ArrayStack<Int> (and likewise ConsStack<Int>) fails in the backend. Comparing through Stack<Int>-typed parameters works, so the conformance program in #202 uses that workaround.

Goal

Structural equality on concrete stack (and other collection) types compiles and behaves like the trait-typed comparison.

Next

Refine: reproduce on main, locate the failing backend step, write acceptance criteria. Seed impact unknown until refined.

## Finding Found by the loop worker for #198 (PR https://git.torb.dev/torbscript/language/pulls/202): `a == b` where both sides are concrete `ArrayStack<Int>` (and likewise `ConsStack<Int>`) fails in the backend. Comparing through `Stack<Int>`-typed parameters works, so the conformance program in #202 uses that workaround. ## Goal Structural equality on concrete stack (and other collection) types compiles and behaves like the trait-typed comparison. ## Next Refine: reproduce on main, locate the failing backend step, write acceptance criteria. Seed impact unknown until refined.
Author
Collaborator

Same family, found by the #199 worker (PR #203): == between two Queue values (incl. ArrayQueue) hits an internal VM error; the conformance program compares through toList() instead. Scope of this issue: structural == on concrete collection values (stacks, queues) in VM and backend.

Same family, found by the #199 worker (PR https://git.torb.dev/torbscript/language/pulls/203): `==` between two `Queue` values (incl. `ArrayQueue`) hits an internal VM error; the conformance program compares through `toList()` instead. Scope of this issue: structural `==` on concrete collection values (stacks, queues) in VM and backend.
Author
Collaborator

Same family, found by the #197 worker (PR #201): == between two concrete List implementation values (e.g. RingList) fails in lowering; predates that PR.

Same family, found by the #197 worker (PR https://git.torb.dev/torbscript/language/pulls/201): `==` between two concrete `List` implementation values (e.g. `RingList`) fails in lowering; predates that PR.
Author
Collaborator

[loop:torbscript] intake: in scope (finding from the loop worker of PR #202, author orion, label loop), no duplicate among the open issues, no collision with a design record seen at triage; a backend defect on concrete collection types, seed impact unknown until refined, next: refine (queued behind the ready buffer, waiting until the buffer drops below 4 ready issues)

[loop:torbscript] intake: in scope (finding from the loop worker of PR #202, author orion, label `loop`), no duplicate among the open issues, no collision with a design record seen at triage; a backend defect on concrete collection types, seed impact unknown until refined, next: refine (queued behind the ready buffer, waiting until the buffer drops below 4 `ready` issues)
Author
Collaborator

[loop:torbscript] refine: held back, the ready buffer is above its target of 4 ready issues, next: waiting (ready buffer full)

[loop:torbscript] refine: held back, the ready buffer is above its target of 4 `ready` issues, next: waiting (ready buffer full)
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261012 until 2026-10-12T13:05Z

[loop:torbscript] claim refine by session:loop-torbscript-20261012 until 2026-10-12T13:05Z
Author
Collaborator

[loop:torbscript] decided by the loop: refined from a read of the code (no local build: gates and bootstraps run in forge CI only).

Cause (hypothesis to confirm first in CI): Equals for every stack, queue and list is declared as an extension of the trait (extend<Item: Equals> Stack<Item> with Equals, std/collections/src/stack.trb:84; likewise Queue in queue.trb:84 and List in list.trb:488). a == b lowers to Equals.equals through lowerOperator (compiler/src/ir/lower/call.trb:1959, via lowerOperatorExpression in ir/lower/expression.trb:1509). With both operands typed as the trait it resolves; with a concrete implementation type (ArrayStack<Int>, ConsStack<Int>, RingList, ArrayQueue) the trait-extension member is not found or its receiver is not coerced (receiverOfTraitExtension, call.trb:287). The VM error on Queue and the lowering failure on List are the same family; the issue covers all concrete collection types, not only stacks.

Goal: a == b and a != b on two values of the same concrete collection type (stacks, queues, lists) compile and run in the VM and --native, with exactly the result of the trait-typed comparison.

Acceptance criteria

  1. A conformance program tests/conformance/concrete-collection-equality.trb (+ .expected) compares, with == and != and no Stack/Queue/List-typed helper: two ArrayStack<Int>, two ConsStack<Int>, two ArrayQueue<Int>, two BankersQueue<Int>, two RingList<Int>: equal, different length, different order, empty vs empty. Tier B runs it in the VM and native with identical output.
  2. The workarounds this issue produced are removed where they exist (the trait-typed same helper in tests/conformance/cons-stack-persists.trb and the toList() comparisons in the queue conformance program) and still print the same output.
  3. A compiler test in compiler/tests covers the lowering of == with concrete collection operands (fails on main, passes after).
  4. Mixed implementation types (ArrayStack == ConsStack) stay a checker error as today, because Equals.equals takes Self (CLOSED-TRAITS.md section on ==); no behaviour change there.
  5. sh tools/gates.sh ab green in forge CI.

Design link: docs/design/COLLECTIONS.md (collections are Equals when their items are; Item: Equals bound) and docs/design/CLOSED-TRAITS.md 7.5. Roadmap: milestone row "collections" in docs/ROADMAP.md (related open item #212). No design record changes; the language rule already says this must work.

Seed impact: none expected. This is a fix inside the checker/lowering (compiler/src), with no new syntax, native, driver flag or renamed std name looked up by string, so one commit fix(ir): ... (plus its test and the conformance program) suffices. If the fix turns out to need a std rename or a new well-known name, the worker stops and splits it per the two-commit rule instead.

Size: one PR, one or two Conventional Commits (fix(ir) for the lowering, test(conformance) for the program and cleanup). Implementer: opus/high (compiler/src/ir). First step for the worker: reproduce with a scratch program in CI and confirm the failing step before changing code.

[loop:torbscript] decided by the loop: refined from a read of the code (no local build: gates and bootstraps run in forge CI only). **Cause (hypothesis to confirm first in CI):** `Equals` for every stack, queue and list is declared as an extension of the *trait* (`extend<Item: Equals> Stack<Item> with Equals`, std/collections/src/stack.trb:84; likewise `Queue` in queue.trb:84 and `List` in list.trb:488). `a == b` lowers to `Equals.equals` through `lowerOperator` (compiler/src/ir/lower/call.trb:1959, via `lowerOperatorExpression` in ir/lower/expression.trb:1509). With both operands typed as the trait it resolves; with a concrete implementation type (`ArrayStack<Int>`, `ConsStack<Int>`, `RingList`, `ArrayQueue`) the trait-extension member is not found or its receiver is not coerced (`receiverOfTraitExtension`, call.trb:287). The VM error on `Queue` and the lowering failure on `List` are the same family; the issue covers all concrete collection types, not only stacks. **Goal:** `a == b` and `a != b` on two values of the same concrete collection type (stacks, queues, lists) compile and run in the VM and `--native`, with exactly the result of the trait-typed comparison. **Acceptance criteria** 1. A conformance program `tests/conformance/concrete-collection-equality.trb` (+ `.expected`) compares, with `==` and `!=` and no `Stack`/`Queue`/`List`-typed helper: two `ArrayStack<Int>`, two `ConsStack<Int>`, two `ArrayQueue<Int>`, two `BankersQueue<Int>`, two `RingList<Int>`: equal, different length, different order, empty vs empty. Tier B runs it in the VM and native with identical output. 2. The workarounds this issue produced are removed where they exist (the trait-typed `same` helper in `tests/conformance/cons-stack-persists.trb` and the `toList()` comparisons in the queue conformance program) and still print the same output. 3. A compiler test in `compiler/tests` covers the lowering of `==` with concrete collection operands (fails on `main`, passes after). 4. Mixed implementation types (`ArrayStack == ConsStack`) stay a checker error as today, because `Equals.equals` takes `Self` (CLOSED-TRAITS.md section on `==`); no behaviour change there. 5. `sh tools/gates.sh ab` green in forge CI. **Design link:** docs/design/COLLECTIONS.md (collections are `Equals` when their items are; `Item: Equals` bound) and docs/design/CLOSED-TRAITS.md 7.5. Roadmap: milestone row "collections" in docs/ROADMAP.md (related open item #212). No design record changes; the language rule already says this must work. **Seed impact:** none expected. This is a fix inside the checker/lowering (compiler/src), with no new syntax, native, driver flag or renamed std name looked up by string, so one commit `fix(ir): ...` (plus its test and the conformance program) suffices. If the fix turns out to need a std rename or a new well-known name, the worker stops and splits it per the two-commit rule instead. **Size:** one PR, one or two Conventional Commits (`fix(ir)` for the lowering, `test(conformance)` for the program and cleanup). Implementer: opus/high (compiler/src/ir). First step for the worker: reproduce with a scratch program in CI and confirm the failing step before changing code.
Author
Collaborator

[loop:torbscript] refine: ready (goal, acceptance criteria incl. regression tests, design link, seed impact none expected, one PR), label ready set, next: implement. Tokens: ~60k (sonnet worker, read-only analysis).

[loop:torbscript] refine: ready (goal, acceptance criteria incl. regression tests, design link, seed impact none expected, one PR), label `ready` set, next: implement. Tokens: ~60k (sonnet worker, read-only analysis).
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T17:07Z

[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T17:07Z
argus closed this issue 2026-10-12 13:11:25 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#209
No description provided.