Skip to content

feat(emit): two unnamed forms compare by their parts (#295) - #357

Merged
cmj0121 merged 4 commits into
mainfrom
feat/295-container-equality
Oct 13, 2026
Merged

cmj0121 merged 4 commits into
mainfrom
feat/295-container-equality

Conversation

@cmj0121

@cmj0121 cmj0121 commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Closes #295. Last task of #285.

What changes

== and != over two values of one unnamed form are built: a list and an array compare in order, a tuple
part by part, and a map or a set whatever order they were filled in. E9057 retires.

The rule is the one docs/core/types.md already had — an unnamed form has Eq exactly when every part has
it — so one predicate (c_eq_legal) answers the operator and the T: Eq bound alike.

  • A part is compared by the == a program would write between two of them. The two parts are bound as
    two names and the operator is handed back to c_expr, so a str, a declared type's eq (with the copies
    that call owes) and a form inside a form are each decided where they already were.
  • A map's keys are found, not compared: by the hash and equality the map was built with.
  • != is the negation. An unnamed form wrote no ne to dispatch to.
  • What is refused is the part, named beside the form, under the code that part already had:
    E4020 ==on a list[N], which compares its N: a N has noEq``, E4038 for a carrier, `E4034` for an
    identity.

Decided here, and worth a second look

  • Tuples and arrays are in. two containers compare with == and != #295 names list, map and set; E9057 also covered tuples, the types
    chapter gives a tuple Eq by the same rule, and the code cannot retire with a tuple still under it.
  • A literal does not take the other operand's element type. bs == [1, 2] over a list[byte] is
    E3046, and xs == [] is E3034. Both were already what the checker said; the collections chapter now
    says so.

Not in this PR

  • x in xss over a list of containers is still E9061, and over a list of a declared type with an Eq.
  • assert xs == ys over two lists is E4011: the comparison builds, and the message has to render both
    sides, which str over a list does not. A map, a set, a tuple and a declared type are claimed directly.
    The package chapter says so and gives assert (xs == ys).
  • An ordering over two tuples is E3044, while the types chapter gives a tuple Ord by its parts. Not
    touched, not filed.

Measured

Each gate run alone, its own status read: build fixpoint lint fmt-self error-codes-check
seed-gaps refuse reject mem-check oracle corpus sanitize-corpus mem-peak examples
docs-mirror docs-links docs-zerg docs-refused docs-repeat marker-codes chapter-codes
deviation-check refusal-cites method-gaps gates treesitter dead-code stdlib-test
compiler-test check-equal reject-fuzz fmt-corpus behaviour conformance productions suites
desugar — all OK. refuse-check, reject-check and mem-check also under /bin/bash 3.2.

  • mem-check case container_equality: RED with the left operand's give-back removed
    (5070 per round unfreed), green with it.
  • lsp: FAIL through make lsp on this machine, OK through a copy of the script that keeps its fixtures
    in an empty directory.
    The server lists the directory above the buffer, zrt_listdir sorts
    quadratically, and this machine's temp directory holds forty thousand entries. Not this change, and not
    filed.
  • The whole board (make test) was not run.

The seed compares no container, so the corpus case is an oracle skip.

🤖 Generated with Claude Code

https://claude.ai/code/session_01N8jd1oK2orM6diHxhvWhC7

    `==` and `!=` over a list, a map, a set, a tuple and an array were
    E9057, on the ground that a container has no declaration to derive
    an `Eq` on. It needs none: docs/core/types.md gives an unnamed form
    what every one of its parts has.

    - a list and an array compare in order, a tuple part by part, a map
      and a set whatever order they were filled in
    - a part is compared by the `==` a program would write between two
      of them, so a str, a declared type's `eq` and a form inside a
      form are each decided where they already were
    - an operand the expression made is held and given back; one
      somebody else holds is read where it stands
    - `T: Eq` asks the same predicate, so a `list[int]` meets the bound
    - what is refused is the part that cannot be compared, named beside
      the form, under the code that part already had

    E9057 retires. Its three `refuse` cases go with it; what they asked
    is built now.
    - reject: a list, a nested map and a derived `Eq` over a part with
      no `Eq`; a list of carriers; a tuple holding a channel; the bound
      a `list[N]` does not meet; a literal of another element type and
      an empty one; an ordering over two lists
    - mem-check: both operands of every form are read and given back,
      whichever way the answer went. Red with the left operand's
      give-back removed: 5070 a round
    - strings_test: the comment said two lists cannot be compared
    The collections, specs, types, format and package chapters each
    said `==` over a container was E9057. They say what compares now,
    and the two things beside it that do not: a literal is typed by its
    own elements, and `assert xs == ys` over two lists still has to
    render them (E4011).
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.

two containers compare with == and !=

1 participant