Skip to content

Fix apparent nondeterminism in pattern matching compilation. #7557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 17, 2025

Conversation

cristianoc
Copy link
Collaborator

Fixes #7465

Pattern matching compilation has some code to find if some exit is used at least 3 times. This is done by iterating on a hash table. However, the exit id is generated based on a global counter, which determines which exit value n is generated. This can affect the order in which the hash table is traversed, as the exit id is hashed. This PR makes the code generation deterministic by adding a tie-breaker if more than id leads to the same exit being used at least 3 times: take the smaller id.

Fixes #7465

Pattern matching compilation has some code to find if some exit is used at least 3 times. This is done by iterating on a hash table.
However, the exit id is generated based on a global counter, which determines which exit value `n` is generated.  This can affect the order in which the hash table is traversed, as the exit id is hashed.
This PR makes the code generation deterministic by adding a tie-breaker if more than id leads to the same exit being used at least 3 times: take the smaller id.
@cristianoc cristianoc force-pushed the nondet-pattern-match branch from 2fddf8e to c2a29d0 Compare June 17, 2025 10:26
@cristianoc cristianoc requested a review from zth June 17, 2025 10:27
Copy link

pkg-pr-new bot commented Jun 17, 2025

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@7557

@rescript/darwin-arm64

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

@rescript/darwin-x64

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

@rescript/linux-arm64

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

@rescript/linux-x64

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

@rescript/win32-x64

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

commit: c2a29d0

Copy link
Collaborator

@zth zth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing!

@cknitt cknitt merged commit 880ca0c into master Jun 17, 2025
17 checks passed
@cristianoc cristianoc requested a review from Copilot June 18, 2025 08:23
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes an issue with nondeterministic behavior in pattern matching compilation by introducing a deterministic tie-breaker in exit id selection. Key changes include updated tests in JavaScript and ReScript for pattern matching, a revised tie-breaker condition in the compiler backend, and a changelog entry documenting the fix.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/tests/src/adt_optimize_test.mjs Updated test cases to reflect changes in pattern matching behavior.
tests/tests/src/NondetPatterMatch.res Added new tests with ReScript syntax for pattern matching.
tests/tests/src/NondetPatterMatch.mjs Added new tests with JS patterns for validating pattern matching.
compiler/ml/matching.ml Updated tie-breaker logic for exit id selection to improve determinism.
CHANGELOG.md Documented the fix in the changelog.

@@ -1808,7 +1808,10 @@ let reintroduce_fail sw =
let i_max = ref (-1) and max = ref (-1) in
Hashtbl.iter
(fun i c ->
if c > !max then (
if
c > !max || (c = !max && i > !i_max)
Copy link
Preview

Copilot AI Jun 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tie-break condition claims to choose the smallest index, but the condition 'i > !i_max' actually selects the larger index. Consider revising it to 'i < !i_max' to ensure the intended deterministic behavior.

Suggested change
c > !max || (c = !max && i > !i_max)
c > !max || (c = !max && i < !i_max)

Copilot uses AI. Check for mistakes.

@cristianoc cristianoc deleted the nondet-pattern-match branch June 18, 2025 08:24
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.

Switch sometimes (non-deterministically?) results in redundant conditional block
3 participants