🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

Support pattern matching on Bytes literals - #6228

Merged
aryairani merged 1 commit into
trunkfrom
feature/bytes-literal-patterns
May 1, 2026
Merged

Support pattern matching on Bytes literals#6228
aryairani merged 1 commit into
trunkfrom
feature/bytes-literal-patterns

Conversation

@runarorama

Copy link
Copy Markdown
Contributor

Overview

This adds support for pattern matching on Bytes literals (0xs...), bringing
them in line with Text, Nat, Int, Float, Char, and Boolean, which
already work as both expressions and patterns.

Old behavior0xsabba was accepted in expression position but rejected as a
pattern:

> match 0xs with
    0xsabba -> "abba"
    _       -> "not abba"

I got confused here:
    6 |     0xsabba -> "abba"

I was surprised to find a bytes literal here.
I was expecting one of these instead:
* end of input
* pattern

New behavior — bytes literals can be used as patterns, including
underscore-separated forms (0xs01_ef):

classify : Bytes -> Text
classify = cases
  0xs0102 -> "one-two"
  0xsabcd -> "abcd"
  0xs     -> "empty"
  _       -> "other"

Closes #6128.

Implementation approach and notes

The same shape as the existing Text pattern path, mirrored across every layer:

  • AST layers — added Bytes to Unison.Pattern (core),
    Unison.Syntax.Pattern, U.Codebase.Term.Pattern (V2 storage), and
    Unison.Hashing.V2.Pattern. Conversions between layers updated in both directions.
  • Parser — added pBytes to pLiteral in TermParser.hs, reusing the
    existing bytesToken lexer.
  • TypecheckerPattern.Bytes requires the scrutinee to be a subtype of
    Type.bytes.
  • Pattern-match coverage — added Bytes to PmLit, Vc'Bytes to
    VarConstraints, and threaded it through Solve, NormalizedConstraints, and
    Desugar. Bytes are treated like Text/Char (infinite-domain literals), so
    coverage analysis works without changes to the IntervalSet machinery.
  • Pretty-printer — patterns render back as 0xs<hex> for round-trip, matching
    the existing expression-level renderer. bytesRef was added to builtinCase in
    Runtime.Pattern so dispatch goes through splitMatrixBuiltin rather than
    lookupData.
  • Runtime — added MatchBytes (Map Bytes e) (Maybe e) to Branched,
    AccumBytes to BranchAccum, TestY/MatchY to MCode, and selectBytesBranch
    in the machine. Dispatch is Map-based (like MatchText), so it's O(log n) rather
    than a chain of equality tests.
  • Hashing/serialization — new tags in V2/Pattern.hs (14), Synhash.hs (17),
    MtTag (MBytesT), Sqlite/Serialization (14), MCode/Serialize (TestYT), and
    MurmurHash. Term.intop (which embeds patterns back into terms for some debug
    paths) uses Bytes.fromList [hex...] to mirror how Bytes literal expressions
    desugar.

Interesting/controversial decisions

V4 ANF codec — reject vs. forward-compatible. The V4 codec is a frozen
format predating this feature. I made it explicitly throw on MatchBytes (both
serialize and deserialize) rather than silently fall through. Anyone serializing
with V4 needs to know they've lost a feature. The current codec gets a new tag
MBytesT = 7.

Test coverage

  • Added unison-src/transcripts/idempotent/bytes-pattern-match.md covering basic
    dispatch, default fallthrough, the empty 0xs, and underscore-separated literals
    (0xs01_ef). Idempotent — re-running produces zero diff.
  • Ran ./scripts/proofs/tests.sh — all unit test suites + 22 CLI integration tests
    pass.
  • Ran ./scripts/proofs/transcripts.sh — 385 transcripts pass, no diffs against
    committed .output.md files.
  • Coverage feels adequate. Could add explicit pattern-match coverage warnings tests
    (e.g. a non-exhaustive match on Bytes should warn), but that machinery is shared
    with Text/Char so the existing tests for those exercise the same code path.

Fixes #6128. Bytes literals (0xs...) were accepted in expression
position but rejected as patterns, alongside Text/Nat/Int/Float/Char/
Boolean. This adds full support across parser, typechecker, pattern-
match coverage, runtime, hashing, and serialization, with round-trip
pretty-printing.

Adds a transcript demonstrating basic dispatch, default fallthrough,
and underscore-separated literals (0xs01_ef).
@runarorama
runarorama force-pushed the feature/bytes-literal-patterns branch from a4bd74d to e50bc7f Compare May 1, 2026 01:58
@aryairani
aryairani added this pull request to the merge queue May 1, 2026
Merged via the queue into trunk with commit 8325e57 May 1, 2026
12 checks passed
@aryairani
aryairani deleted the feature/bytes-literal-patterns branch May 1, 2026 06:22
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 match on Bytes literal

2 participants