Skip to content

Commit 499dc4a

Browse files
giacomocavalierilpil
authored andcommitted
refactor pattern matching to favour first appearing variable
1 parent 8bdec6d commit 499dc4a

File tree

18 files changed

+95
-91
lines changed

18 files changed

+95
-91
lines changed

compiler-core/src/exhaustiveness.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,27 +2748,29 @@ fn find_pivot_check(
27482748
}
27492749
}
27502750

2751-
// Maximize ( -branching_factor, references ).
2751+
// We want to picke the variable that has the smallest branching factor
2752+
// possible, this tends to yield smaller, shallower decision trees.
2753+
// So, for example, we will pick a list (branching factor of 2 `[]` and
2754+
// `[_, ..]`) over an integer (infinitely many choices).
27522755
//
2753-
// - branching_factor: prefer the split that creates the FEWEST switch arms.
2754-
// Fewer children tends to yield smaller, shallower decision trees.
2755-
//
2756-
// - references: break ties by choosing the subject that appears in the most
2757-
// clauses (i.e. a test that will pay off for more rows).
2756+
// In case two variables are tied we break the tie by choosing the subject
2757+
// that appears in the most clauses (i.e. a test that will pay off for more
2758+
// rows).
27582759
//
27592760
// Both parts mirror standard guidance for good match trees (small branching
2760-
// factor; prioritize columns that are widely useful).
2761-
//
2761+
// factor; prioritize columns that are widely useful):
27622762
// https://www.cs.tufts.edu/~nr/cs257/archive/luc-maranget/jun08.pdf
27632763
first_branch
27642764
.checks
27652765
.iter()
2766-
.max_by_key(|check| {
2767-
let mode = check.var.branch_mode(env);
2768-
let branching_factor = mode.branching_factor();
2766+
.min_by_key(|check| {
2767+
let branching_factor = check.var.branch_mode(env).branching_factor();
27692768
let references = var_references.get(&check.var.id).cloned().unwrap_or(0);
27702769

2771-
(usize::MAX - branching_factor, references)
2770+
// Notice how we're using `-references`: we want to favour the one
2771+
// that has the most references, so the one were `-references` is
2772+
// the smallest.
2773+
(branching_factor, -references)
27722774
})
27732775
.cloned()
27742776
}

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__assert1.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import { makeError } from "../gleam.mjs";
1111
const FILEPATH = "src/module.gleam";
1212

1313
export function go(x) {
14-
let $ = x[1];
15-
if ($ === 2) {
16-
let $1 = x[0];
17-
if (!($1 === 1)) {
14+
let $ = x[0];
15+
if ($ === 1) {
16+
let $1 = x[1];
17+
if (!($1 === 2)) {
1818
throw makeError(
1919
"let_assert",
2020
FILEPATH,

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__nested_binding.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ export function go(x) {
1919
let t;
2020
let b;
2121
let c;
22-
let $ = x[1][2];
23-
if ($ === 2) {
24-
let $1 = x[3];
25-
if ($1 === 1) {
22+
let $ = x[3];
23+
if ($ === 1) {
24+
let $1 = x[1][2];
25+
if ($1 === 2) {
2626
a = x[0];
2727
t = x[1];
2828
b = x[1][0];

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__assignments__tuple_matching.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import { makeError } from "../gleam.mjs";
1515
const FILEPATH = "src/module.gleam";
1616

1717
export function go(x) {
18-
let $ = x[1];
19-
if ($ === 2) {
20-
let $1 = x[0];
21-
if (!($1 === 1)) {
18+
let $ = x[0];
19+
if ($ === 1) {
20+
let $1 = x[1];
21+
if (!($1 === 2)) {
2222
throw makeError(
2323
"let_assert",
2424
FILEPATH,

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__tuple_multiple_bit_arrays.snap

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ import { makeError } from "../gleam.mjs";
1515
const FILEPATH = "src/module.gleam";
1616

1717
export function go(x) {
18-
let $ = x[2];
19-
if (
20-
$.bitSize >= 8 &&
21-
$.byteAt(0) === 2 &&
22-
$.bitSize === 16 &&
23-
$.byteAt(1) === 3
24-
) {
18+
let $ = x[0];
19+
if ($.bitSize === 0) {
2520
let $1 = x[1];
26-
if ($1.bitSize === 8 && $1.byteAt(0) === 1) {
27-
let $2 = x[0];
28-
if (!($2.bitSize === 0)) {
21+
if ($1.bitSize === 8) {
22+
let $2 = x[2];
23+
if (!(
24+
$2.bitSize >= 8 &&
25+
$1.byteAt(0) === 1 &&
26+
$2.byteAt(0) === 2 &&
27+
$2.bitSize === 16 &&
28+
$2.byteAt(1) === 3
29+
)) {
2930
throw makeError(
3031
"let_assert",
3132
FILEPATH,

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__bit_arrays__tuple_multiple_bit_arrays_case.snap

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,18 @@ pub fn go(x) {
1414

1515
----- COMPILED JAVASCRIPT
1616
export function go(x) {
17-
let $ = x[2];
18-
if (
19-
$.bitSize >= 8 &&
20-
$.byteAt(0) === 2 &&
21-
$.bitSize === 16 &&
22-
$.byteAt(1) === 3
23-
) {
17+
let $ = x[0];
18+
if ($.bitSize === 0) {
2419
let $1 = x[1];
25-
if ($1.bitSize === 8 && $1.byteAt(0) === 1) {
26-
let $2 = x[0];
27-
if ($2.bitSize === 0) {
20+
if ($1.bitSize === 8) {
21+
let $2 = x[2];
22+
if (
23+
$2.bitSize >= 8 &&
24+
$1.byteAt(0) === 1 &&
25+
$2.byteAt(0) === 2 &&
26+
$2.bitSize === 16 &&
27+
$2.byteAt(1) === 3
28+
) {
2829
return true;
2930
} else {
3031
return false;

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_list_matched_by_pattern.snap

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,29 @@ export function go(n, x) {
2525
} else {
2626
let $ = x.tail;
2727
if ($ instanceof $Empty) {
28-
let $1 = x.head;
29-
if ($1 === 1 && n === 3) {
30-
return x;
28+
if (n === 3) {
29+
let $1 = x.head;
30+
if ($1 === 1) {
31+
return x;
32+
} else {
33+
return x;
34+
}
3135
} else {
3236
return x;
3337
}
3438
} else {
3539
let $1 = $.tail;
3640
if ($1 instanceof $Empty) {
3741
return x;
38-
} else {
42+
} else if (n === 3) {
3943
let $2 = x.head;
40-
if ($2 === 1 && n === 3) {
44+
if ($2 === 1) {
4145
return x;
4246
} else {
4347
return x;
4448
}
49+
} else {
50+
return x;
4551
}
4652
}
4753
}

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_record_matched_by_pattern.snap

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@ pub fn go(x, y) {
1515
import { Ok, Error } from "../gleam.mjs";
1616

1717
export function go(x, y) {
18-
if (y instanceof Ok) {
19-
if (x instanceof Error) {
20-
return y;
21-
} else {
22-
return new Error(undefined);
23-
}
24-
} else if (x instanceof Ok) {
25-
let $ = x[0];
26-
if ($ === 1) {
27-
return x;
18+
if (x instanceof Ok) {
19+
if (y instanceof Error) {
20+
let $ = x[0];
21+
if ($ === 1) {
22+
return x;
23+
} else {
24+
return new Error(undefined);
25+
}
2826
} else {
2927
return new Error(undefined);
3028
}
29+
} else if (y instanceof Ok) {
30+
return y;
3131
} else {
3232
return new Error(undefined);
3333
}

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__case_with_multiple_subjects_building_same_value_as_two_subjects_one_is_picked.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import { Ok, Error } from "../gleam.mjs";
2121
export function go(x, y) {
2222
if (y instanceof Ok) {
2323
if (x instanceof $gleam.Ok) {
24-
let $ = x[0];
24+
let $ = y[0];
2525
if ($ === 1) {
26-
let $1 = y[0];
26+
let $1 = x[0];
2727
if ($1 === 1) {
2828
return x;
2929
} else {

compiler-core/src/javascript/tests/snapshots/gleam_core__javascript__tests__case__multi_subject_catch_all.snap

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
---
22
source: compiler-core/src/javascript/tests/case.rs
3-
assertion_line: 95
43
expression: "\npub fn go(x, y) {\n case x, y {\n True, True -> 1\n _, _ -> 0\n }\n}\n"
5-
snapshot_kind: text
64
---
75
----- SOURCE CODE
86

@@ -16,7 +14,7 @@ pub fn go(x, y) {
1614

1715
----- COMPILED JAVASCRIPT
1816
export function go(x, y) {
19-
if (y && x) {
17+
if (x && y) {
2018
return 1;
2119
} else {
2220
return 0;

0 commit comments

Comments
 (0)