From 42d0279abfd09f2278dd930fe9ddbf9eef9f6390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Oct 2025 10:48:40 +0200 Subject: [PATCH 1/4] Port "Fixed nullish coalesce operator's precedence" --- internal/ast/precedence.go | 8 ++++---- internal/checker/checker.go | 21 ++++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/internal/ast/precedence.go b/internal/ast/precedence.go index 26b001d362..2d2ab41079 100644 --- a/internal/ast/precedence.go +++ b/internal/ast/precedence.go @@ -43,6 +43,10 @@ const ( // ShortCircuitExpression // ShortCircuitExpression `?` AssignmentExpression `:` AssignmentExpression OperatorPrecedenceConditional + // LogicalORExpression: + // LogicalANDExpression + // LogicalORExpression `||` LogicalANDExpression + OperatorPrecedenceLogicalOR // ShortCircuitExpression: // LogicalORExpression // CoalesceExpression @@ -52,10 +56,6 @@ const ( // CoalesceExpression // BitwiseORExpression OperatorPrecedenceCoalesce - // LogicalORExpression: - // LogicalANDExpression - // LogicalORExpression `||` LogicalANDExpression - OperatorPrecedenceLogicalOR // LogicalANDExpression: // BitwiseORExpression // LogicalANDExprerssion `&&` BitwiseORExpression diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 42f3851a61..b57dabd56f 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -12400,11 +12400,22 @@ func (c *Checker) getSyntacticTruthySemantics(node *ast.Node) PredicateSemantics } func (c *Checker) checkNullishCoalesceOperands(left *ast.Node, right *ast.Node) { - if ast.IsBinaryExpression(left) && ast.IsLogicalBinaryOperator(left.AsBinaryExpression().OperatorToken.Kind) { - c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(left.AsBinaryExpression().OperatorToken.Kind), scanner.TokenToString(ast.KindQuestionQuestionToken)) - } - if ast.IsBinaryExpression(right) && ast.IsLogicalBinaryOperator(right.AsBinaryExpression().OperatorToken.Kind) { - c.grammarErrorOnNode(right, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(right.AsBinaryExpression().OperatorToken.Kind), scanner.TokenToString(ast.KindQuestionQuestionToken)) + if ast.IsBinaryExpression(left.Parent.Parent) { + operatorToken := left.Parent.Parent.AsBinaryExpression().OperatorToken + left := left.Parent.Parent.AsBinaryExpression().Left + if ast.IsBinaryExpression(left) && operatorToken.Kind == ast.KindBarBarToken { + c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) + } + } else if ast.IsBinaryExpression(left) { + operatorToken := left.AsBinaryExpression().OperatorToken + if operatorToken.Kind == ast.KindBarBarToken || operatorToken.Kind == ast.KindAmpersandAmpersandToken { + c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(operatorToken.Kind), scanner.TokenToString(ast.KindQuestionQuestionToken)) + } + } else if ast.IsBinaryExpression(right) { + operatorToken := right.AsBinaryExpression().OperatorToken + if operatorToken.Kind == ast.KindAmpersandAmpersandToken { + c.grammarErrorOnNode(right, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) + } } leftTarget := ast.SkipOuterExpressions(left, ast.OEKAll) nullishSemantics := c.getSyntacticNullishnessSemantics(leftTarget) From 507b13d120a745ebb58760708ecd2928e05864f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Oct 2025 11:05:12 +0200 Subject: [PATCH 2/4] fix things --- internal/ast/precedence.go | 18 +++++------ internal/printer/printer.go | 8 ----- .../nullishCoalescingOperator5.errors.txt | 10 +++--- ...nullishCoalescingOperator5.errors.txt.diff | 31 ------------------- .../conformance/nullishCoalescingOperator5.js | 2 +- .../nullishCoalescingOperator5.js.diff | 6 +--- .../nullishCoalescingOperator5.types | 2 +- .../nullishCoalescingOperator5.types.diff | 11 ------- .../plainJSGrammarErrors.errors.txt | 6 ++-- .../conformance/plainJSGrammarErrors.js | 4 +-- .../conformance/plainJSGrammarErrors.js.diff | 10 +----- .../conformance/plainJSGrammarErrors.types | 2 +- .../plainJSGrammarErrors.errors.txt.diff | 24 ++------------ .../plainJSGrammarErrors.types.diff | 12 +------ 14 files changed, 27 insertions(+), 119 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt.diff delete mode 100644 testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types.diff diff --git a/internal/ast/precedence.go b/internal/ast/precedence.go index 2d2ab41079..e23d5278c9 100644 --- a/internal/ast/precedence.go +++ b/internal/ast/precedence.go @@ -47,15 +47,6 @@ const ( // LogicalANDExpression // LogicalORExpression `||` LogicalANDExpression OperatorPrecedenceLogicalOR - // ShortCircuitExpression: - // LogicalORExpression - // CoalesceExpression - // CoalesceExpression: - // CoalesceExpressionHead `??` BitwiseORExpression - // CoalesceExpressionHead: - // CoalesceExpression - // BitwiseORExpression - OperatorPrecedenceCoalesce // LogicalANDExpression: // BitwiseORExpression // LogicalANDExprerssion `&&` BitwiseORExpression @@ -181,6 +172,15 @@ const ( OperatorPrecedenceLowest = OperatorPrecedenceComma OperatorPrecedenceHighest = OperatorPrecedenceParentheses OperatorPrecedenceDisallowComma = OperatorPrecedenceYield + // ShortCircuitExpression: + // LogicalORExpression + // CoalesceExpression + // CoalesceExpression: + // CoalesceExpressionHead `??` BitwiseORExpression + // CoalesceExpressionHead: + // CoalesceExpression + // BitwiseORExpression + OperatorPrecedenceCoalesce = OperatorPrecedenceLogicalOR // -1 is lower than all other precedences. Returning it will cause binary expression // parsing to stop. OperatorPrecedenceInvalid OperatorPrecedence = -1 diff --git a/internal/printer/printer.go b/internal/printer/printer.go index f9581f9e10..2275f2dc06 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -2716,14 +2716,6 @@ func (p *Printer) getBinaryExpressionPrecedence(node *ast.BinaryExpression) (lef case ast.OperatorPrecedenceAssignment: // assignment is right-associative leftPrec = ast.OperatorPrecedenceLeftHandSide - case ast.OperatorPrecedenceCoalesce: - // allow coalesce on the left, but short circuit to BitwiseOR - if isBinaryOperation(node.Left, ast.KindQuestionQuestionToken) { - leftPrec = ast.OperatorPrecedenceCoalesce - } else { - leftPrec = ast.OperatorPrecedenceBitwiseOR - } - rightPrec = ast.OperatorPrecedenceBitwiseOR case ast.OperatorPrecedenceLogicalOR: rightPrec = ast.OperatorPrecedenceLogicalAND case ast.OperatorPrecedenceLogicalAND: diff --git a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt index a352e2b340..06b774dcbf 100644 --- a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt @@ -1,6 +1,6 @@ -nullishCoalescingOperator5.ts(6,6): error TS5076: '||' and '??' operations cannot be mixed without parentheses. +nullishCoalescingOperator5.ts(6,1): error TS5076: '??' and '||' operations cannot be mixed without parentheses. nullishCoalescingOperator5.ts(9,1): error TS5076: '||' and '??' operations cannot be mixed without parentheses. -nullishCoalescingOperator5.ts(12,6): error TS5076: '&&' and '??' operations cannot be mixed without parentheses. +nullishCoalescingOperator5.ts(12,6): error TS5076: '??' and '&&' operations cannot be mixed without parentheses. nullishCoalescingOperator5.ts(15,1): error TS5076: '&&' and '??' operations cannot be mixed without parentheses. @@ -11,8 +11,8 @@ nullishCoalescingOperator5.ts(15,1): error TS5076: '&&' and '??' operations cann // should be a syntax error a ?? b || c; - ~~~~~~ -!!! error TS5076: '||' and '??' operations cannot be mixed without parentheses. + ~~~~~~ +!!! error TS5076: '??' and '||' operations cannot be mixed without parentheses. // should be a syntax error a || b ?? c; @@ -22,7 +22,7 @@ nullishCoalescingOperator5.ts(15,1): error TS5076: '&&' and '??' operations cann // should be a syntax error a ?? b && c; ~~~~~~ -!!! error TS5076: '&&' and '??' operations cannot be mixed without parentheses. +!!! error TS5076: '??' and '&&' operations cannot be mixed without parentheses. // should be a syntax error a && b ?? c; diff --git a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt.diff b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt.diff deleted file mode 100644 index 27b8e320f9..0000000000 --- a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.errors.txt.diff +++ /dev/null @@ -1,31 +0,0 @@ ---- old.nullishCoalescingOperator5.errors.txt -+++ new.nullishCoalescingOperator5.errors.txt -@@= skipped -0, +0 lines =@@ --nullishCoalescingOperator5.ts(6,1): error TS5076: '??' and '||' operations cannot be mixed without parentheses. -+nullishCoalescingOperator5.ts(6,6): error TS5076: '||' and '??' operations cannot be mixed without parentheses. - nullishCoalescingOperator5.ts(9,1): error TS5076: '||' and '??' operations cannot be mixed without parentheses. --nullishCoalescingOperator5.ts(12,6): error TS5076: '??' and '&&' operations cannot be mixed without parentheses. -+nullishCoalescingOperator5.ts(12,6): error TS5076: '&&' and '??' operations cannot be mixed without parentheses. - nullishCoalescingOperator5.ts(15,1): error TS5076: '&&' and '??' operations cannot be mixed without parentheses. - - -@@= skipped -10, +10 lines =@@ - - // should be a syntax error - a ?? b || c; -- ~~~~~~ --!!! error TS5076: '??' and '||' operations cannot be mixed without parentheses. -+ ~~~~~~ -+!!! error TS5076: '||' and '??' operations cannot be mixed without parentheses. - - // should be a syntax error - a || b ?? c; -@@= skipped -11, +11 lines =@@ - // should be a syntax error - a ?? b && c; - ~~~~~~ --!!! error TS5076: '??' and '&&' operations cannot be mixed without parentheses. -+!!! error TS5076: '&&' and '??' operations cannot be mixed without parentheses. - - // should be a syntax error - a && b ?? c; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js index 49e49d535b..2fd55a5f61 100644 --- a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js +++ b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js @@ -45,7 +45,7 @@ a && (b ?? c); //// [nullishCoalescingOperator5.js] var _a, _b, _c, _d; // should be a syntax error -a !== null && a !== void 0 ? a : b || c; +(a !== null && a !== void 0 ? a : b) || c; // should be a syntax error (_a = a || b) !== null && _a !== void 0 ? _a : c; // should be a syntax error diff --git a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js.diff b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js.diff index d3291c48fc..56762afba0 100644 --- a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js.diff +++ b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.js.diff @@ -7,8 +7,4 @@ -"use strict"; var _a, _b, _c, _d; // should be a syntax error --(a !== null && a !== void 0 ? a : b) || c; -+a !== null && a !== void 0 ? a : b || c; - // should be a syntax error - (_a = a || b) !== null && _a !== void 0 ? _a : c; - // should be a syntax error \ No newline at end of file + (a !== null && a !== void 0 ? a : b) || c; \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types index f92dafbe64..eb55440d56 100644 --- a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types +++ b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types @@ -13,8 +13,8 @@ declare const c: string | undefined // should be a syntax error a ?? b || c; >a ?? b || c : string | undefined +>a ?? b : string | undefined >a : string | undefined ->b || c : string | undefined >b : string | undefined >c : string | undefined diff --git a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types.diff b/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types.diff deleted file mode 100644 index 3c14581c38..0000000000 --- a/testdata/baselines/reference/submodule/conformance/nullishCoalescingOperator5.types.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- old.nullishCoalescingOperator5.types -+++ new.nullishCoalescingOperator5.types -@@= skipped -12, +12 lines =@@ - // should be a syntax error - a ?? b || c; - >a ?? b || c : string | undefined -->a ?? b : string | undefined - >a : string | undefined -+>b || c : string | undefined - >b : string | undefined - >c : string | undefined diff --git a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt index 40731faa29..d4de4272f9 100644 --- a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt +++ b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.errors.txt @@ -58,7 +58,7 @@ plainJSGrammarErrors.js(92,33): error TS2566: A rest element cannot have a prope plainJSGrammarErrors.js(93,42): error TS1186: A rest element cannot have an initializer. plainJSGrammarErrors.js(96,4): error TS1123: Variable declaration list cannot be empty. plainJSGrammarErrors.js(97,9): error TS5076: '||' and '??' operations cannot be mixed without parentheses. -plainJSGrammarErrors.js(98,14): error TS5076: '||' and '??' operations cannot be mixed without parentheses. +plainJSGrammarErrors.js(98,9): error TS5076: '??' and '||' operations cannot be mixed without parentheses. plainJSGrammarErrors.js(100,3): error TS1200: Line terminator not permitted before arrow. plainJSGrammarErrors.js(102,4): error TS1358: Tagged template expressions are not permitted in an optional chain. plainJSGrammarErrors.js(104,6): error TS1171: A comma expression is not allowed in a computed property name. @@ -320,8 +320,8 @@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot ~~~~~~ !!! error TS5076: '||' and '??' operations cannot be mixed without parentheses. var x = 2 ?? 3 || 4 - ~~~~~~ -!!! error TS5076: '||' and '??' operations cannot be mixed without parentheses. + ~~~~~~ +!!! error TS5076: '??' and '||' operations cannot be mixed without parentheses. const arr = x => x + 1 ~~ diff --git a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js index eccd22d9e6..3738de6fa2 100644 --- a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js +++ b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js @@ -303,8 +303,8 @@ const { e: eep, m: em, ...rest: noRestAllowed } = doom; const { e: erp, m: erm, ...noInitialiser = true } = doom; // left-over parsing var ; -var x = (1 || 2) ?? 3; -var x = 2 ?? (3 || 4); +var x = 1 || 2 ?? 3; +var x = 2 ?? 3 || 4; const arr = x => x + 1; var a = [1, 2]; a `length`; diff --git a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js.diff b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js.diff index ff2c0bd52b..db62b31259 100644 --- a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js.diff +++ b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.js.diff @@ -38,15 +38,7 @@ export import 'fs'; export { C }; function nestedExports() { -@@= skipped -30, +30 lines =@@ - const { e: erp, m: erm, ...noInitialiser = true } = doom; - // left-over parsing - var ; --var x = 1 || 2 ?? 3; --var x = 2 ?? 3 || 4; -+var x = (1 || 2) ?? 3; -+var x = 2 ?? (3 || 4); - const arr = x => x + 1; +@@= skipped -36, +36 lines =@@ var a = [1, 2]; a `length`; const o = { diff --git a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.types b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.types index 5e2cbda34a..135597fd49 100644 --- a/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.types +++ b/testdata/baselines/reference/submodule/conformance/plainJSGrammarErrors.types @@ -278,8 +278,8 @@ var x = 1 || 2 ?? 3 var x = 2 ?? 3 || 4 >x : number >2 ?? 3 || 4 : 2 | 3 | 4 +>2 ?? 3 : 2 | 3 >2 : 2 ->3 || 4 : 3 | 4 >3 : 3 >4 : 4 diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff index cd52c1ca63..249a843d77 100644 --- a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff +++ b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.errors.txt.diff @@ -18,16 +18,7 @@ plainJSGrammarErrors.js(64,1): error TS1042: 'async' modifier cannot be used here. plainJSGrammarErrors.js(65,1): error TS1042: 'async' modifier cannot be used here. plainJSGrammarErrors.js(66,1): error TS1042: 'async' modifier cannot be used here. -@@= skipped -21, +20 lines =@@ - plainJSGrammarErrors.js(93,42): error TS1186: A rest element cannot have an initializer. - plainJSGrammarErrors.js(96,4): error TS1123: Variable declaration list cannot be empty. - plainJSGrammarErrors.js(97,9): error TS5076: '||' and '??' operations cannot be mixed without parentheses. --plainJSGrammarErrors.js(98,9): error TS5076: '??' and '||' operations cannot be mixed without parentheses. -+plainJSGrammarErrors.js(98,14): error TS5076: '||' and '??' operations cannot be mixed without parentheses. - plainJSGrammarErrors.js(100,3): error TS1200: Line terminator not permitted before arrow. - plainJSGrammarErrors.js(102,4): error TS1358: Tagged template expressions are not permitted in an optional chain. - plainJSGrammarErrors.js(104,6): error TS1171: A comma expression is not allowed in a computed property name. -@@= skipped -43, +43 lines =@@ +@@= skipped -64, +63 lines =@@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot be spread element. @@ -62,15 +53,4 @@ -!!! error TS8009: The 'async' modifier can only be used in TypeScript files. } async const cantAsyncConst = 2 - ~~~~~ -@@= skipped -78, +76 lines =@@ - ~~~~~~ - !!! error TS5076: '||' and '??' operations cannot be mixed without parentheses. - var x = 2 ?? 3 || 4 -- ~~~~~~ --!!! error TS5076: '??' and '||' operations cannot be mixed without parentheses. -+ ~~~~~~ -+!!! error TS5076: '||' and '??' operations cannot be mixed without parentheses. - const arr = x - => x + 1 - ~~ \ No newline at end of file + ~~~~~ \ No newline at end of file diff --git a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.types.diff b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.types.diff index 19ae51b03e..3843c64aaf 100644 --- a/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.types.diff +++ b/testdata/baselines/reference/submoduleAccepted/conformance/plainJSGrammarErrors.types.diff @@ -9,17 +9,7 @@ export { staticParam } >staticParam : any -@@= skipped -97, +97 lines =@@ - var x = 2 ?? 3 || 4 - >x : number - >2 ?? 3 || 4 : 2 | 3 | 4 -->2 ?? 3 : 2 | 3 - >2 : 2 -+>3 || 4 : 3 | 4 - >3 : 3 - >4 : 4 - -@@= skipped -194, +194 lines =@@ +@@= skipped -291, +291 lines =@@ >b : any switch (b) { From 03a7baf9338ceae6ac48f0bcd71a480bbb864fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Oct 2025 11:39:00 +0200 Subject: [PATCH 3/4] fmt --- internal/checker/checker.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index b57dabd56f..629355b328 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -12404,17 +12404,17 @@ func (c *Checker) checkNullishCoalesceOperands(left *ast.Node, right *ast.Node) operatorToken := left.Parent.Parent.AsBinaryExpression().OperatorToken left := left.Parent.Parent.AsBinaryExpression().Left if ast.IsBinaryExpression(left) && operatorToken.Kind == ast.KindBarBarToken { - c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) + c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) } } else if ast.IsBinaryExpression(left) { operatorToken := left.AsBinaryExpression().OperatorToken if operatorToken.Kind == ast.KindBarBarToken || operatorToken.Kind == ast.KindAmpersandAmpersandToken { - c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(operatorToken.Kind), scanner.TokenToString(ast.KindQuestionQuestionToken)) + c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(operatorToken.Kind), scanner.TokenToString(ast.KindQuestionQuestionToken)) } } else if ast.IsBinaryExpression(right) { operatorToken := right.AsBinaryExpression().OperatorToken if operatorToken.Kind == ast.KindAmpersandAmpersandToken { - c.grammarErrorOnNode(right, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) + c.grammarErrorOnNode(right, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) } } leftTarget := ast.SkipOuterExpressions(left, ast.OEKAll) From f6534fe5bbcc5934ef295829ab2c72501bfd74bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 5 Oct 2025 11:40:27 +0200 Subject: [PATCH 4/4] lint --- internal/checker/checker.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 629355b328..c4a370ea74 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -12401,10 +12401,10 @@ func (c *Checker) getSyntacticTruthySemantics(node *ast.Node) PredicateSemantics func (c *Checker) checkNullishCoalesceOperands(left *ast.Node, right *ast.Node) { if ast.IsBinaryExpression(left.Parent.Parent) { - operatorToken := left.Parent.Parent.AsBinaryExpression().OperatorToken - left := left.Parent.Parent.AsBinaryExpression().Left - if ast.IsBinaryExpression(left) && operatorToken.Kind == ast.KindBarBarToken { - c.grammarErrorOnNode(left, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(operatorToken.Kind)) + grandparentLeft := left.Parent.Parent.AsBinaryExpression().Left + grandparentOperatorToken := left.Parent.Parent.AsBinaryExpression().OperatorToken + if ast.IsBinaryExpression(grandparentLeft) && grandparentOperatorToken.Kind == ast.KindBarBarToken { + c.grammarErrorOnNode(grandparentLeft, diagnostics.X_0_and_1_operations_cannot_be_mixed_without_parentheses, scanner.TokenToString(ast.KindQuestionQuestionToken), scanner.TokenToString(grandparentOperatorToken.Kind)) } } else if ast.IsBinaryExpression(left) { operatorToken := left.AsBinaryExpression().OperatorToken