mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-15 06:39:17 +00:00
fix(packages/codegen): preserve private-in right operand precedence (#26420)
`packages/codegen` drops required parentheses around the right operand of a private-in expression when that operand is another relational expression. This changes which value the private-field check receives and can change observable behavior.
For example, this input throws a `TypeError`:
```js
class C {
#x;
test(a, b) {
return #x in (a instanceof b);
}
}
new C().test({}, Object);
```
`a instanceof b` evaluates to `true`, but a private-field check requires an object on its right-hand side.
The JavaScript printer previously emitted:
```js
return #x in a instanceof b;
```
Relational operators associate to the left, so that output is parsed as `(#x in a) instanceof b`. The private-field check on `{}` produces `false`, and `false instanceof Object` returns `false` instead of throwing.
The printer now preserves the original grouping:
```js
return #x in (a instanceof b);
```
`printPrivateInExpression` now prints its right operand with `PREC_COMPARE` instead of `PREC_EQUALS`. The expression printers wrap operands whose precedence is equal to or lower than the requested precedence, so the comparison threshold retains parentheses around `<`, `<=`, `>`, `>=`, `instanceof`, and nested private-in expressions. The now-unused `PREC_EQUALS` import is removed.
Equality and lower-precedence operands continue to retain their required grouping. Shift, arithmetic, and exponentiation operands can still omit unnecessary parentheses. The existing `CTX_FORBID_IN` handling remains in place.
This applies to both ordinary and source-map-enabled printer builds and brings the JavaScript implementation in line with the Rust fix in #26411. It addresses grouping of the private-in right operand, separately from the left-operand correction in #26403.
This commit is contained in:
1 parent
f8e6c6ccf8
commit
598618793c
2 files changed
+40
-4
No files matched your search
@@ -56,7 +56,6 @@ import {
|
||||
PREC_COMMA,
|
||||
PREC_COMPARE,
|
||||
PREC_CONDITIONAL,
|
||||
PREC_EQUALS,
|
||||
PREC_EXPONENTIATION,
|
||||
PREC_LOWEST,
|
||||
PREC_NEW,
|
||||
@@ -382,8 +381,9 @@ function printArguments(
|
||||
* `#field in obj`, which arrives as a `BinaryExpression` with a `PrivateIdentifier` on the left
|
||||
* rather than as a node type of its own - hence the extra test in `printExpression`.
|
||||
*
|
||||
* It sits at the `in` operator's own level, so it wraps from `PREC_COMPARE` upwards, and the right
|
||||
* operand prints one level tighter with `CTX_FORBID_IN` set.
|
||||
* It sits at the `in` operator's own level, so it wraps from `PREC_COMPARE` upwards. The right
|
||||
* operand also prints at `PREC_COMPARE`, preserving parentheses around relational and
|
||||
* lower-precedence expressions, with `CTX_FORBID_IN` set.
|
||||
*/
|
||||
export function printPrivateInExpression(
|
||||
node: ESTree.PrivateInExpression,
|
||||
@@ -396,7 +396,7 @@ export function printPrivateInExpression(
|
||||
markMapStart(state, node.start, node.end, node);
|
||||
writeWithMapNamedPrivate(state, node.left.name, node.left.start, node.left.end, node.left);
|
||||
write(state, " in ", CAT_OTHER);
|
||||
printExpression(node.right, state, PREC_EQUALS, CTX_FORBID_IN);
|
||||
printExpression(node.right, state, PREC_COMPARE, CTX_FORBID_IN);
|
||||
|
||||
if (wrap) write(state, ")", CAT_CLOSE_BRACKET);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
class C {
|
||||
#x;
|
||||
test(a, b) {
|
||||
return [
|
||||
#x in (a instanceof b),
|
||||
#x in (a in b),
|
||||
#x in (a < b),
|
||||
#x in (a <= b),
|
||||
#x in (a > b),
|
||||
#x in (a >= b),
|
||||
#x in (a == b),
|
||||
#x in (a != b),
|
||||
#x in (a === b),
|
||||
#x in (a !== b),
|
||||
#x in (a & b),
|
||||
#x in (a ^ b),
|
||||
#x in (a | b),
|
||||
#x in (a && b),
|
||||
#x in (a || b),
|
||||
#x in (a ?? b),
|
||||
#x in (a = b),
|
||||
#x in (a << b),
|
||||
#x in (a >> b),
|
||||
#x in (a >>> b),
|
||||
#x in (a + b),
|
||||
#x in (a - b),
|
||||
#x in (a * b),
|
||||
#x in (a / b),
|
||||
#x in (a % b),
|
||||
#x in (a ** b),
|
||||
#x in (#x in a),
|
||||
#x in (a ? a : b),
|
||||
#x in (a, b),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user