mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
fix(packages/codegen): preserve private-in left operand precedence (#26403)
The codegen npm package drops required parentheses when a private-in expression is the left operand of a higher-precedence binary operator. The generated JavaScript can evaluate a different expression and throw a runtime error.
For example, this input returns `2`:
```js
class C {
#x;
test(o) {
return (#x in o) + 1;
}
}
console.log(new C().test(new C()));
```
The JavaScript printer previously emitted the return expression as:
```js
return #x in o + 1;
```
Because `+` binds more tightly than `in`, that output is parsed as `#x in (o + 1)`. Adding `1` to the object produces a primitive, so the private-field check throws a `TypeError` instead of producing the boolean used by the original addition.
The printer now preserves the grouping:
```js
return (#x in o) + 1;
```
The iterative binary-expression printer already computes the precedence required for each left operand. Its private-in special case discarded that value and passed `PREC_LOWEST` to `printPrivateInExpression`. Passing `v.leftPrecedence` instead lets the existing private-in printer insert the required parentheses.
This preserves grouping for arithmetic, exponentiation, and shift operators. Equal- and lower-precedence operators, such as `<`, `===`, and `&&`, continue to omit unnecessary parentheses. The correction applies to both the ordinary and source-map-enabled JavaScript printer builds and brings this path in line with the Rust codegen fix in #26383.
This commit is contained in:
@@ -65,7 +65,7 @@ export function printBinaryish(
|
||||
if (left.type === "BinaryExpression" && left.left.type === "PrivateIdentifier") {
|
||||
// Private-in expression as the left operand
|
||||
typeAssertIs<ESTree.PrivateInExpression>(left);
|
||||
printPrivateInExpression(left, state, PREC_LOWEST);
|
||||
printPrivateInExpression(left, state, v.leftPrecedence);
|
||||
binVisitRightAndFinish(v, state);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
class C {
|
||||
#x;
|
||||
test(o) {
|
||||
return [
|
||||
(#x in o) + 1,
|
||||
(#x in o) - 1,
|
||||
(#x in o) * 1,
|
||||
(#x in o) / 1,
|
||||
(#x in o) % 1,
|
||||
(#x in o) ** 1,
|
||||
(#x in o) << 1,
|
||||
(#x in o) >> 1,
|
||||
(#x in o) >>> 1,
|
||||
(#x in o) < 1,
|
||||
(#x in o) <= 1,
|
||||
(#x in o) > 1,
|
||||
(#x in o) >= 1,
|
||||
(#x in o) == 1,
|
||||
(#x in o) != 1,
|
||||
(#x in o) === 1,
|
||||
(#x in o) !== 1,
|
||||
(#x in o) & 1,
|
||||
(#x in o) ^ 1,
|
||||
(#x in o) | 1,
|
||||
(#x in o) && 1,
|
||||
(#x in o) || 1,
|
||||
(#x in o) ?? 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user