From fd2482aa93fb86366a4498c8ad25478d6f55209b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:02:49 +0000 Subject: [PATCH 1/2] Initial plan From 5b14d74d03eeb4cf1f78baf20ada12493f62871f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 19:16:56 +0000 Subject: [PATCH 2/2] Port TypeScript PR #62789: Fix "never nullish" diagnostic missing expressions wrapped in parentheses Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- internal/checker/checker.go | 28 ++--- .../compiler/predicateSemantics.errors.txt | 56 ++++----- .../predicateSemantics.errors.txt.diff | 117 ++++++++++++++++++ 3 files changed, 152 insertions(+), 49 deletions(-) create mode 100644 testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt.diff diff --git a/internal/checker/checker.go b/internal/checker/checker.go index c921129e8b5..6de5e3c0090 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -12532,7 +12532,6 @@ func (c *Checker) checkNullishCoalesceOperands(left *ast.Node, right *ast.Node) } } c.checkNullishCoalesceOperandLeft(left) - c.checkNullishCoalesceOperandRight(right) } func (c *Checker) checkNullishCoalesceOperandLeft(left *ast.Node) { @@ -12547,20 +12546,6 @@ func (c *Checker) checkNullishCoalesceOperandLeft(left *ast.Node) { } } -func (c *Checker) checkNullishCoalesceOperandRight(right *ast.Node) { - binaryExpression := right.Parent - if binaryExpression.Parent != nil && ast.IsBinaryExpression(binaryExpression.Parent) && binaryExpression.Parent.AsBinaryExpression().OperatorToken.Kind == ast.KindQuestionQuestionToken { - rightTarget := ast.SkipOuterExpressions(right, ast.OEKAll) - nullishSemantics := c.getSyntacticNullishnessSemantics(rightTarget) - switch nullishSemantics { - case PredicateSemanticsAlways: - c.error(rightTarget, diagnostics.This_expression_is_always_nullish) - case PredicateSemanticsNever: - c.error(rightTarget, diagnostics.This_expression_is_never_nullish) - } - } -} - func (c *Checker) getSyntacticNullishnessSemantics(node *ast.Node) PredicateSemantics { node = ast.SkipOuterExpressions(node, ast.OEKAll) switch node.Kind { @@ -12576,17 +12561,18 @@ func (c *Checker) getSyntacticNullishnessSemantics(node *ast.Node) PredicateSema return PredicateSemanticsSometimes case ast.KindBinaryExpression: // List of operators that can produce null/undefined: - // = ??= ?? || ||= && &&= + // || ||= && &&= switch node.AsBinaryExpression().OperatorToken.Kind { - case ast.KindEqualsToken, - ast.KindQuestionQuestionToken, - ast.KindQuestionQuestionEqualsToken, - ast.KindBarBarToken, + case ast.KindBarBarToken, ast.KindBarBarEqualsToken, ast.KindAmpersandAmpersandToken, ast.KindAmpersandAmpersandEqualsToken: return PredicateSemanticsSometimes - case ast.KindCommaToken: + // For these operator kinds, the right operand is effectively controlling + case ast.KindCommaToken, + ast.KindEqualsToken, + ast.KindQuestionQuestionToken, + ast.KindQuestionQuestionEqualsToken: return c.getSyntacticNullishnessSemantics(node.AsBinaryExpression().Right) } return PredicateSemanticsNever diff --git a/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt b/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt index cf503611a4b..9bc7e32be22 100644 --- a/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt @@ -7,26 +7,26 @@ predicateSemantics.ts(29,13): error TS2871: This expression is always nullish. predicateSemantics.ts(30,13): error TS2872: This kind of expression is always truthy. predicateSemantics.ts(31,13): error TS2872: This kind of expression is always truthy. predicateSemantics.ts(32,13): error TS2871: This expression is always nullish. -predicateSemantics.ts(32,21): error TS2871: This expression is always nullish. +predicateSemantics.ts(32,13): error TS2871: This expression is always nullish. predicateSemantics.ts(33,13): error TS2871: This expression is always nullish. predicateSemantics.ts(34,13): error TS2871: This expression is always nullish. -predicateSemantics.ts(34,22): error TS2871: This expression is always nullish. -predicateSemantics.ts(36,20): error TS2871: This expression is always nullish. -predicateSemantics.ts(37,20): error TS2871: This expression is always nullish. +predicateSemantics.ts(34,13): error TS2871: This expression is always nullish. +predicateSemantics.ts(36,13): error TS2871: This expression is always nullish. +predicateSemantics.ts(37,13): error TS2871: This expression is always nullish. predicateSemantics.ts(38,21): error TS2871: This expression is always nullish. predicateSemantics.ts(39,21): error TS2871: This expression is always nullish. predicateSemantics.ts(40,21): error TS2871: This expression is always nullish. -predicateSemantics.ts(40,29): error TS2871: This expression is always nullish. -predicateSemantics.ts(41,21): error TS2871: This expression is always nullish. -predicateSemantics.ts(42,20): error TS2881: This expression is never nullish. -predicateSemantics.ts(43,21): error TS2881: This expression is never nullish. +predicateSemantics.ts(40,21): error TS2871: This expression is always nullish. +predicateSemantics.ts(41,13): error TS2871: This expression is always nullish. +predicateSemantics.ts(42,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. +predicateSemantics.ts(43,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. +predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. +predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. -predicateSemantics.ts(45,21): error TS2871: This expression is always nullish. -predicateSemantics.ts(45,29): error TS2871: This expression is always nullish. predicateSemantics.ts(46,13): error TS2871: This expression is always nullish. -predicateSemantics.ts(46,21): error TS2881: This expression is never nullish. +predicateSemantics.ts(46,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. predicateSemantics.ts(47,13): error TS2871: This expression is always nullish. -predicateSemantics.ts(47,22): error TS2881: This expression is never nullish. +predicateSemantics.ts(47,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. predicateSemantics.ts(50,8): error TS2872: This kind of expression is always truthy. predicateSemantics.ts(51,11): error TS2872: This kind of expression is always truthy. predicateSemantics.ts(52,8): error TS2872: This kind of expression is always truthy. @@ -89,7 +89,7 @@ predicateSemantics.ts(90,1): error TS2869: Right operand of ?? is unreachable be const p07 = null ?? null ?? null; ~~~~ !!! error TS2871: This expression is always nullish. - ~~~~ + ~~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p08 = null ?? opt ?? null; ~~~~ @@ -97,14 +97,14 @@ predicateSemantics.ts(90,1): error TS2869: Right operand of ?? is unreachable be const p09 = null ?? (opt ? null : undefined) ?? null; ~~~~ !!! error TS2871: This expression is always nullish. - ~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p10 = opt ?? null ?? 1; - ~~~~ + ~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p11 = opt ?? null ?? null; - ~~~~ + ~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p12 = opt ?? (null ?? 1); ~~~~ @@ -115,35 +115,35 @@ predicateSemantics.ts(90,1): error TS2869: Right operand of ?? is unreachable be const p14 = opt ?? (null ?? null ?? null); ~~~~ !!! error TS2871: This expression is always nullish. - ~~~~ + ~~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p15 = opt ?? (opt ? null : undefined) ?? null; - ~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p16 = opt ?? 1 ?? 2; - ~ -!!! error TS2881: This expression is never nullish. + ~~~~~~~~ +!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. const p17 = opt ?? (opt ? 1 : 2) ?? 3; - ~~~~~~~~~~~ -!!! error TS2881: This expression is never nullish. + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. const p21 = null ?? null ?? null ?? null; ~~~~ !!! error TS2871: This expression is always nullish. - ~~~~ + ~~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. - ~~~~ + ~~~~~~~~~~~~~~~~~~~~ !!! error TS2871: This expression is always nullish. const p22 = null ?? 1 ?? 1; ~~~~ !!! error TS2871: This expression is always nullish. - ~ -!!! error TS2881: This expression is never nullish. + ~~~~~~~~~ +!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. const p23 = null ?? (opt ? 1 : 2) ?? 1; ~~~~ !!! error TS2871: This expression is always nullish. - ~~~~~~~~~~~ -!!! error TS2881: This expression is never nullish. + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. // Outer expression tests while ({} as any) { } diff --git a/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt.diff new file mode 100644 index 00000000000..4e155d7bd97 --- /dev/null +++ b/testdata/baselines/reference/submodule/compiler/predicateSemantics.errors.txt.diff @@ -0,0 +1,117 @@ +--- old.predicateSemantics.errors.txt ++++ new.predicateSemantics.errors.txt +@@= skipped -6, +6 lines =@@ + predicateSemantics.ts(30,13): error TS2872: This kind of expression is always truthy. + predicateSemantics.ts(31,13): error TS2872: This kind of expression is always truthy. + predicateSemantics.ts(32,13): error TS2871: This expression is always nullish. +-predicateSemantics.ts(32,21): error TS2871: This expression is always nullish. ++predicateSemantics.ts(32,13): error TS2871: This expression is always nullish. + predicateSemantics.ts(33,13): error TS2871: This expression is always nullish. + predicateSemantics.ts(34,13): error TS2871: This expression is always nullish. +-predicateSemantics.ts(34,22): error TS2871: This expression is always nullish. +-predicateSemantics.ts(36,20): error TS2871: This expression is always nullish. +-predicateSemantics.ts(37,20): error TS2871: This expression is always nullish. ++predicateSemantics.ts(34,13): error TS2871: This expression is always nullish. ++predicateSemantics.ts(36,13): error TS2871: This expression is always nullish. ++predicateSemantics.ts(37,13): error TS2871: This expression is always nullish. + predicateSemantics.ts(38,21): error TS2871: This expression is always nullish. + predicateSemantics.ts(39,21): error TS2871: This expression is always nullish. + predicateSemantics.ts(40,21): error TS2871: This expression is always nullish. +-predicateSemantics.ts(40,29): error TS2871: This expression is always nullish. +-predicateSemantics.ts(41,21): error TS2871: This expression is always nullish. +-predicateSemantics.ts(42,20): error TS2881: This expression is never nullish. +-predicateSemantics.ts(43,21): error TS2881: This expression is never nullish. +-predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. +-predicateSemantics.ts(45,21): error TS2871: This expression is always nullish. +-predicateSemantics.ts(45,29): error TS2871: This expression is always nullish. ++predicateSemantics.ts(40,21): error TS2871: This expression is always nullish. ++predicateSemantics.ts(41,13): error TS2871: This expression is always nullish. ++predicateSemantics.ts(42,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. ++predicateSemantics.ts(43,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. ++predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. ++predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. ++predicateSemantics.ts(45,13): error TS2871: This expression is always nullish. + predicateSemantics.ts(46,13): error TS2871: This expression is always nullish. +-predicateSemantics.ts(46,21): error TS2881: This expression is never nullish. ++predicateSemantics.ts(46,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + predicateSemantics.ts(47,13): error TS2871: This expression is always nullish. +-predicateSemantics.ts(47,22): error TS2881: This expression is never nullish. ++predicateSemantics.ts(47,13): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + predicateSemantics.ts(50,8): error TS2872: This kind of expression is always truthy. + predicateSemantics.ts(51,11): error TS2872: This kind of expression is always truthy. + predicateSemantics.ts(52,8): error TS2872: This kind of expression is always truthy. +@@= skipped -82, +82 lines =@@ + const p07 = null ?? null ?? null; + ~~~~ + !!! error TS2871: This expression is always nullish. +- ~~~~ ++ ~~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + const p08 = null ?? opt ?? null; + ~~~~ +@@= skipped -8, +8 lines =@@ + const p09 = null ?? (opt ? null : undefined) ?? null; + ~~~~ + !!! error TS2871: This expression is always nullish. +- ~~~~~~~~~~~~~~~~~~~~~~ ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + + const p10 = opt ?? null ?? 1; +- ~~~~ ++ ~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + const p11 = opt ?? null ?? null; +- ~~~~ ++ ~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + const p12 = opt ?? (null ?? 1); + ~~~~ +@@= skipped -18, +18 lines =@@ + const p14 = opt ?? (null ?? null ?? null); + ~~~~ + !!! error TS2871: This expression is always nullish. +- ~~~~ ++ ~~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + const p15 = opt ?? (opt ? null : undefined) ?? null; +- ~~~~~~~~~~~~~~~~~~~~~~ ++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + const p16 = opt ?? 1 ?? 2; +- ~ +-!!! error TS2881: This expression is never nullish. ++ ~~~~~~~~ ++!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + const p17 = opt ?? (opt ? 1 : 2) ?? 3; +- ~~~~~~~~~~~ +-!!! error TS2881: This expression is never nullish. ++ ~~~~~~~~~~~~~~~~~~~~ ++!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + + const p21 = null ?? null ?? null ?? null; + ~~~~ + !!! error TS2871: This expression is always nullish. +- ~~~~ ++ ~~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. +- ~~~~ ++ ~~~~~~~~~~~~~~~~~~~~ + !!! error TS2871: This expression is always nullish. + const p22 = null ?? 1 ?? 1; + ~~~~ + !!! error TS2871: This expression is always nullish. +- ~ +-!!! error TS2881: This expression is never nullish. ++ ~~~~~~~~~ ++!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + const p23 = null ?? (opt ? 1 : 2) ?? 1; + ~~~~ + !!! error TS2871: This expression is always nullish. +- ~~~~~~~~~~~ +-!!! error TS2881: This expression is never nullish. ++ ~~~~~~~~~~~~~~~~~~~~~ ++!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish. + + // Outer expression tests + while ({} as any) { } \ No newline at end of file