diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f48294cb..49ae685075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - Prop punning when types don't match results in I/O error: _none_: No such file or directory. https://github.com/rescript-lang/rescript/pull/7533 - Fix partial application with user-defined function types. https://github.com/rescript-lang/rescript/pull/7548 - Fix doc comment before variant throwing syntax error. https://github.com/rescript-lang/rescript/pull/7535 +- Fix apparent non-determinism in generated code for pattern matching. https://github.com/rescript-lang/rescript/pull/7557 #### :nail_care: Polish diff --git a/compiler/ml/matching.ml b/compiler/ml/matching.ml index 5fba3beb56..9e80d998fd 100644 --- a/compiler/ml/matching.ml +++ b/compiler/ml/matching.ml @@ -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) + (* tie-break for determinism: choose the smallest index*) + then ( i_max := i; max := c)) t; diff --git a/tests/tests/src/NondetPatterMatch.mjs b/tests/tests/src/NondetPatterMatch.mjs new file mode 100644 index 0000000000..b5f5ecca71 --- /dev/null +++ b/tests/tests/src/NondetPatterMatch.mjs @@ -0,0 +1,36 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + + +function f1(action) { + if (typeof action === "object") { + switch (action.TAG) { + case "WithPayload5" : + case "WithPayload6" : + case "WithPayload7" : + case "WithPayload8" : + console.log("hello"); + break; + } + } + return 42; +} + +function f2(action) { + if (typeof action === "object") { + switch (action.TAG) { + case "WithPayload5" : + case "WithPayload6" : + case "WithPayload7" : + case "WithPayload8" : + console.log("hello"); + break; + } + } + return 42; +} + +export { + f1, + f2, +} +/* No side effect */ diff --git a/tests/tests/src/NondetPatterMatch.res b/tests/tests/src/NondetPatterMatch.res new file mode 100644 index 0000000000..afed361b7d --- /dev/null +++ b/tests/tests/src/NondetPatterMatch.res @@ -0,0 +1,33 @@ +type action = + | WithoutPayload1 + | WithoutPayload2 + | WithPayload2({y: int}) + | WithPayload3({y: int}) + | WithPayload5({y: int}) + | WithPayload6({x: int}) + | WithPayload7({y: int}) + | WithPayload8({x: int}) + +let f1 = (action: action) => { + switch action { + | WithPayload5(_) + | WithPayload6(_) + | WithPayload7(_) + | WithPayload8(_) => + Console.log("hello") + | _ => () + } + 42 +} + +let f2 = (action: action) => { + switch action { + | WithPayload5(_) + | WithPayload6(_) + | WithPayload7(_) + | WithPayload8(_) => + Console.log("hello") + | _ => () + } + 42 +} diff --git a/tests/tests/src/adt_optimize_test.mjs b/tests/tests/src/adt_optimize_test.mjs index 59784e1c18..fe8b267ba0 100644 --- a/tests/tests/src/adt_optimize_test.mjs +++ b/tests/tests/src/adt_optimize_test.mjs @@ -134,19 +134,22 @@ function f8(x) { function f9(x) { if (typeof x !== "object") { - if (x === "T63") { - return 3; - } else { - return 1; + switch (x) { + case "T60" : + case "T61" : + case "T62" : + return 1; + default: + return 3; + } + } else { + switch (x.TAG) { + case "T64" : + case "T65" : + return 2; + default: + return 3; } - } - switch (x.TAG) { - case "T64" : - case "T65" : - return 2; - case "T66" : - case "T68" : - return 3; } }