Print null checks with the precedence of ===
Why
Nullable.isNullable(e), and any other %is_nullable, compiles to the JS IR node Is_null_or_undefined e, which Js_dump prints as e == null. It printed e at level 1, below the precedence of ==, so an operand that binds more loosely lost its parentheses and the check applied to part of it: Nullable.isNullable(c ? a : b) compiled to c ? a : b == null, which JavaScript reads as c ? a : (b == null). The same happened to ||, && and bitwise operands, and an object in an arrow function's body gave a syntax error. It also put the whole check in parentheses wherever it was not at the top level, which the output of Stdlib_Nullable shows. Both now follow Js_op_util.op_prec EqEqEq, as x === null does: parentheses when the level is above that of ==, and the operand at its left level.
modifiedJS operand of a null check
let pick = (c, a: Nullable.t<int>, b: Nullable.t<int>) => Nullable.isNullable(c ? a : b)let sum = (a: int, b: int) => Nullable.isNullable(Nullable.make(a + b))
js
modifiedJS null check as an operand
let equal = (a, b, eq) => Option.equal(Nullable.toOption(a), Nullable.toOption(b), eq)js
Review
- Is the precedence of
===right for==? Both are equality operators with the same precedence and left associativity, so a context that takesa === bwithout parentheses takesa == nulltoo: arguments,letinitializers,?:,||,&&, bitwise operators and the left side of===. The right side of===and the operand of!still get parentheses, as iny === (x == null)and!(x == null). - Which checked-in outputs change? Only
Stdlib_Nullable,Stdlib_TempTestsandoptional_external_arg_once_test, where the test of?:loses its parentheses, andPrimitive_option, wherex == nullas an operand of||does. No checked-in output had an operand that lost them. - Why does the conditional break over lines?
Condprints its own parentheses that way when it needs them, as elsewhere in the output. - What else prints an operand below its precedence?
Inprints both operands at level 0 (#9222),Typeofputs itself in no parentheses, andFunignores the level. They are separate fixes.