Skip to content

Remove the hashing fast paths from pattern matching - #8900

Merged
cknitt merged 1 commit into
char-int-rangesfrom
remove-match-fast-paths
Oct 19, 2026
Merged

cknitt merged 1 commit into
char-int-rangesfrom
remove-match-fast-paths

Conversation

@cknitt

@cknitt cknitt commented Oct 18, 2026

Copy link
Copy Markdown
Member

Follow-up to the #7028 stack, on top of #8894.

#8868 added hashing fast paths to exhaustiveness checking and match compilation, because an expanded char range turned one pattern into thousands of distinct constants. Since #8893, a char range is one pattern, so this PR removes them:

  • the constant and polymorphic-variant hash tables in Parmatch.filter_all
  • Parmatch.get_mins_pats, replaced by get_mins le_pats again
  • the hash_key option of Matching.divide
  • Parmatch.const_key, which kept the hash keys consistent with char/int equality

It also removes a dead char check in comparison specialization (translcore.ml): char expands to int before that check.

Cost (best of 3 bsc wall times; switches with N cases plus _):

Cases With fast paths Without
1,000 int 0.07 s 0.09 s
3,000 int 0.34 s 0.63 s
10,000 int 3.23 s 6.27 s
1,000 string 0.04 s 0.07 s
3,000 string 0.17 s 0.52 s
10,000 string 1.55 s 5.38 s
1,000 polymorphic variant 0.23 s 0.25 s
3,000 polymorphic variant 2.22 s 2.29 s
10,000 polymorphic variant 35.47 s 36.45 s

The fast paths only matter beyond a few thousand cases. Even with them, very large switches stay slow because of other quadratic steps; polymorphic variants don't benefit at all.

Output: unchanged. The committed snapshots are byte-identical, as is the JS of the benchmark switches and of 1,500 fuzzer programs over char, int and mixed ranges.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JALXUyHhkDqzcB3WuW9Svo

@cknitt
cknitt added this pull request to stack #8895 October 18, 2026 12:07
@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.03%. Comparing base (24a773a) to head (c8313d5).

Additional details and impacted files
@@                 Coverage Diff                 @@
##           char-int-ranges    #8900      +/-   ##
===================================================
- Coverage            81.04%   81.03%   -0.02%     
===================================================
  Files                  455      455              
  Lines                63675    63630      -45     
===================================================
- Hits                 51605    51561      -44     
+ Misses               12070    12069       -1     
Files with missing lines Coverage Δ
compiler/ml/matching.ml 77.86% <100.00%> (-0.18%) ⬇️
compiler/ml/parmatch.ml 76.62% <100.00%> (-0.65%) ⬇️
compiler/ml/translcore.ml 87.46% <ø> (+0.11%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pkg-pr-new

pkg-pr-new Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript@8900

@rescript/belt

npm i https://pkg.pr.new/@rescript/belt@8900

@rescript/darwin-arm64

npm i https://pkg.pr.new/@rescript/darwin-arm64@8900

@rescript/darwin-x64

npm i https://pkg.pr.new/@rescript/darwin-x64@8900

@rescript/linux-arm64

npm i https://pkg.pr.new/@rescript/linux-arm64@8900

@rescript/linux-x64

npm i https://pkg.pr.new/@rescript/linux-x64@8900

@rescript/runtime

npm i https://pkg.pr.new/@rescript/runtime@8900

@rescript/win32-x64

npm i https://pkg.pr.new/@rescript/win32-x64@8900

commit: c8313d5

@cknitt

cknitt commented Oct 18, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T12:33:31.131742Z 424d9e8 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cknitt
cknitt marked this pull request as ready for review October 18, 2026 12:31
@cknitt
cknitt requested a review from cristianoc October 18, 2026 12:32
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 424d9e823b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

#8868 made exhaustiveness checking and match compilation find constants by
hashing, because an expanded char range turned one pattern into thousands
of distinct constants. Char ranges are now one pattern each, so the hash
tables in `Parmatch.filter_all`, `Parmatch.get_mins_pats` and
`Matching.divide`, and the `const_key` that kept their keys consistent with
char/int equality, are removed. A dead `char` check in comparison
specialization goes too: `char` expands to `int` before it.

Review: How much slower do large switches compile? A switch with 1,000 int
or string cases compiles 0.02-0.03 s slower; one with 10,000 int cases takes
6.3 s instead of 3.2 s. Polymorphic variants are unaffected: 10,000 cases
take about 35 s either way, as other quadratic steps dominate.

Review: Does the output change? No. All committed snapshots are
byte-identical, and so is the JS of 1,500 fuzzer programs and the
benchmark switches.

Area: typechecker lambda
Output: unchanged
Formatting: unchanged
Formats: none
PPX: unchanged
Editor: unchanged
Tests: none, because the output is unchanged and existing tests cover the
 behaviour
Measured: best of 3 bsc wall time, with -> without the fast paths: 1,000 int
 cases 0.07 -> 0.09 s; 3,000 int 0.34 -> 0.63 s; 10,000 int 3.23 -> 6.27 s;
 1,000 string 0.04 -> 0.07 s; 3,000 string 0.17 -> 0.52 s; 10,000 string
 1.55 -> 5.38 s; 1,000 polymorphic variant 0.23 -> 0.25 s; 10,000
 polymorphic variant 35.47 -> 36.45 s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JALXUyHhkDqzcB3WuW9Svo
Signed-off-by: Christoph Knittel <ck@cca.io>
@cknitt
cknitt force-pushed the remove-match-fast-paths branch from d6c5849 to c8313d5 Compare October 19, 2026 06:38
@github-actions

Copy link
Copy Markdown

@cknitt
cknitt merged commit 1eb91bb into master Oct 19, 2026
34 of 50 checks passed
@cknitt
cknitt deleted the remove-match-fast-paths branch October 19, 2026 07:15
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.

2 participants