Account for right operands & fix a weird error message for leftmost nullish literals in checkNullishCoalesceOperands (#59569)

This commit is contained in:
Chiri Vulpes
2025-02-22 11:17:08 +13:00
committed by GitHub
parent edc497bb2b
commit 2bed7feee8
7 changed files with 612 additions and 183 deletions

View File

@@ -39847,24 +39847,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind));
}
const leftTarget = skipOuterExpressions(left, OuterExpressionKinds.All);
const nullishSemantics = getSyntacticNullishnessSemantics(leftTarget);
if (nullishSemantics !== PredicateSemantics.Sometimes) {
if (node.parent.kind === SyntaxKind.BinaryExpression) {
error(leftTarget, Diagnostics.This_binary_expression_is_never_nullish_Are_you_missing_parentheses);
}
else {
if (nullishSemantics === PredicateSemantics.Always) {
error(leftTarget, Diagnostics.This_expression_is_always_nullish);
}
else {
error(leftTarget, Diagnostics.Right_operand_of_is_unreachable_because_the_left_operand_is_never_nullish);
}
}
checkNullishCoalesceOperandLeft(node);
checkNullishCoalesceOperandRight(node);
}
}
function checkNullishCoalesceOperandLeft(node: BinaryExpression) {
const leftTarget = skipOuterExpressions(node.left, OuterExpressionKinds.All);
const nullishSemantics = getSyntacticNullishnessSemantics(leftTarget);
if (nullishSemantics !== PredicateSemantics.Sometimes) {
if (nullishSemantics === PredicateSemantics.Always) {
error(leftTarget, Diagnostics.This_expression_is_always_nullish);
}
else {
error(leftTarget, Diagnostics.Right_operand_of_is_unreachable_because_the_left_operand_is_never_nullish);
}
}
}
function checkNullishCoalesceOperandRight(node: BinaryExpression) {
const rightTarget = skipOuterExpressions(node.right, OuterExpressionKinds.All);
const nullishSemantics = getSyntacticNullishnessSemantics(rightTarget);
if (isNotWithinNullishCoalesceExpression(node)) {
return;
}
if (nullishSemantics === PredicateSemantics.Always) {
error(rightTarget, Diagnostics.This_expression_is_always_nullish);
}
else if (nullishSemantics === PredicateSemantics.Never) {
error(rightTarget, Diagnostics.This_expression_is_never_nullish);
}
}
function isNotWithinNullishCoalesceExpression(node: BinaryExpression) {
return !isBinaryExpression(node.parent) || node.parent.operatorToken.kind !== SyntaxKind.QuestionQuestionToken;
}
function getSyntacticNullishnessSemantics(node: Node): PredicateSemantics {
node = skipOuterExpressions(node);
switch (node.kind) {

View File

@@ -3987,6 +3987,10 @@
"category": "Error",
"code": 2880
},
"This expression is never nullish.": {
"category": "Error",
"code": 2881
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",