Skip to content

feat: check records, variants with fields and match (stage 11a) - #94

Merged
Sequela02 merged 3 commits into
mainfrom
feat/stage-11-records-match
Nov 14, 2026
Merged

Sequela02 merged 3 commits into
mainfrom
feat/stage-11-records-match

Conversation

@Sequela02

Copy link
Copy Markdown
Contributor

Slice 11a of stage 11 (#83): records, variants with fields and match, per syntax decisions 8 to 10. The conformance cases come in their own commit, before the compiler code.

What it adds

  • record Name { field: Type, … }, built Name { field: value, … } with every field named, and read with value.field.
  • Variants with fields, Below(limit: i64), built like a call. Labels are optional for one field and required for more.
  • match value { | Pattern => result … } with decide's rows, in code and in specifications.
    • One field binds by position, more than one by label; _ binds nothing.
    • Every variant once, with no catch-all. A missing variant is an error that names it.
    • A binding can't hide a name in scope.
  • == compares records and variants field by field.

Encoding. Records and variants are SMT-LIB datatypes, declared together. A match is a chain of tests on the variant, and each binding becomes the field it stands for, so an arm's arithmetic, calls and indexes carry obligations under that arm's test alone. The integers and lists inside a record or variant are assumed in range, as a parameter's are. Normalization names records R0 and fields x0 by position, so a rename changes no identity.

Decisions taken within the slice

  • Receipt version 5. It adds a record type kind; a variant with fields is {"variant", "fields"}, and a record is an object of its fields. This follows stage 10's 3 → 4 bump.
  • A pattern lists every field of its variant, with _ for the ones it doesn't need.
  • List elements hold no integer or list, however deep, for the same reason lists of integers wait.
  • Not yet allowed: recursive types, and structured data in a machine's state or parameters.
  • accord build refuses records, variants with fields and match until 11g.
  • Call results, open-case results and contract strength now assume the range facts of their type too, a list's length bound included. Scripts for some existing programs change, so the ledger re-proves them once. No conformance outcome changed.

Verification

  • cargo fmt --all --check passes, and cargo clippy --workspace --all-targets --locked -- -D warnings is clean.
  • cargo test --workspace --locked with the pinned solvers on Windows: all pass, and the 1 ignored test was already ignored.
  • 25 new conformance cases:
    • 11 that check, 4 of them with planted faults. All 4 faults are refuted, with counterexamples replayed in source terms.
    • 14 rejections, each confirmed by hand to fail for the reason it states.
  • New tests:
    • renaming a record, its fields or a binding changes no identity, while a field's type or order does;
    • record and variant counterexamples decode in the receipt;
    • accord build refuses structured data.

Not established:

  • The scripts/check-*.sh integrations weren't run. The TypeScript cases still match their expected output byte for byte.
  • No proof-time measurement.

Risk note

Mostly a two-way door: a language addition behind conformance cases. The one-way part is the receipt schema moving to version 5, which is unstable until the first release. Blast radius: existing programs' outcomes and TypeScript output are unchanged, and some ledger keys change. Evidence: the conformance suite and the test run above.

Refs #83

Stage 11 lands records, variants with fields and match first. Write the
expected outcomes before the compiler code, with planted faults: a field
that overflows without its requires, labels that bind the other field,
an arm's sum that overflows, and a quantifier that ignores a variant.
The rejections cover exhaustiveness, catch-alls, repeated and missing
variants, positional bindings for several fields, missing labels and
fields, shadowing, recursive types, lists that hold integers, and
machines that hold structured data.

Refs #83
Stage 11's target needs a version as a record and pre-release
identifiers as variants with fields. Records and variants become SMT-LIB
datatypes. A match is a chain of tests on the value's variant, and each
name an arm binds becomes the field it stands for, so obligations inside
an arm hold under its test alone. A parameter's integers and lists
inside a record or variant are assumed in range, as a parameter's are.
Normalization names records and fields by position, so a rename changes
no identity.

The receipt moves to version 5: a record type, and values with fields
decoded by name. accord build refuses structured data until its
TypeScript output lands, and machines can't hold it yet.

Refs #83
@Sequela02 Sequela02 added the full-ci Run Windows and macOS CI once before merging label Nov 14, 2026
The review materials check the receipt contract they read, and receipt 5
adds records and variants with fields, which no card uses. The cards and
packets are unchanged; only the hashes of the two scripts move.

Refs #83
@Sequela02 Sequela02 added full-ci Run Windows and macOS CI once before merging and removed full-ci Run Windows and macOS CI once before merging labels Nov 14, 2026
@Sequela02
Sequela02 merged commit e040158 into main Nov 14, 2026
5 checks passed
@Sequela02
Sequela02 deleted the feat/stage-11-records-match branch November 14, 2026 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

full-ci Run Windows and macOS CI once before merging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant