|
| 1 | +open Mocha |
| 2 | +open Test_utils |
| 3 | + |
| 4 | +// A guard may change the value being matched. The cases after it read the |
| 5 | +// changed value, so they must test it again and may all fail to match it. |
| 6 | + |
| 7 | +type pair = {a: bool, mutable b: (option<int>, option<int>)} |
| 8 | + |
| 9 | +let nextB = ref(None) |
| 10 | + |
| 11 | +let setB = r => { |
| 12 | + switch nextB.contents { |
| 13 | + | Some(b) => r.b = b |
| 14 | + | None => () |
| 15 | + } |
| 16 | + false |
| 17 | +} |
| 18 | + |
| 19 | +// The tests on b.0 before the guard must not be trusted after it (#9129). |
| 20 | +let pair = r => |
| 21 | + switch r { |
| 22 | + | {a: true, b: (None, _)} => 1 |
| 23 | + | {a: true, b: (Some(_), _)} if setB(r) => 0 |
| 24 | + | {a: false} => 3 |
| 25 | + | {b: (_, None)} => 4 |
| 26 | + | {b: (Some(x), Some(_))} => x |
| 27 | + } |
| 28 | + |
| 29 | +let pairWith = (b, next) => { |
| 30 | + nextB := next |
| 31 | + pair({a: true, b}) |
| 32 | +} |
| 33 | + |
| 34 | +type flagged = {d: bool, mutable c: option<int>} |
| 35 | + |
| 36 | +let clear = r => { |
| 37 | + r.c = None |
| 38 | + false |
| 39 | +} |
| 40 | + |
| 41 | +// The guarded case reads no mutable field, but the case after it does. |
| 42 | +let flagged = r => |
| 43 | + switch r { |
| 44 | + | {c: None} => 0 |
| 45 | + | {d: true} if clear(r) => 1 |
| 46 | + | {c: Some(x)} => x |
| 47 | + } |
| 48 | + |
| 49 | +describe(__MODULE__, () => { |
| 50 | + test("guards that mutate nothing", () => { |
| 51 | + eq(__LOC__, 1, pairWith((None, None), None)) |
| 52 | + eq(__LOC__, 4, pairWith((Some(1), None), None)) |
| 53 | + eq(__LOC__, 7, pairWith((Some(7), Some(2)), None)) |
| 54 | + eq(__LOC__, 3, pair({a: false, b: (None, None)})) |
| 55 | + eq(__LOC__, 5, flagged({d: false, c: Some(5)})) |
| 56 | + }) |
| 57 | + |
| 58 | + test("a guard that mutates into a later case", () => { |
| 59 | + eq(__LOC__, 8, pairWith((Some(1), None), Some((Some(8), Some(2))))) |
| 60 | + eq(__LOC__, 4, pairWith((Some(1), Some(2)), Some((None, None)))) |
| 61 | + }) |
| 62 | + |
| 63 | + test("a guard that mutates into no case", () => { |
| 64 | + throws(__LOC__, () => ignore(pairWith((Some(1), None), Some((None, Some(2)))))) |
| 65 | + throws(__LOC__, () => ignore(flagged({d: true, c: Some(5)}))) |
| 66 | + }) |
| 67 | +}) |
0 commit comments