mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Fixed nullish coalesce operator's precedence (#61372)
This commit is contained in:
+22
-11
@@ -40472,18 +40472,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function checkNullishCoalesceOperands(node: BinaryExpression) {
|
||||
const { left, operatorToken, right } = node;
|
||||
if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) {
|
||||
if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) {
|
||||
grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind));
|
||||
}
|
||||
if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) {
|
||||
grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind));
|
||||
}
|
||||
|
||||
checkNullishCoalesceOperandLeft(node);
|
||||
checkNullishCoalesceOperandRight(node);
|
||||
if (node.operatorToken.kind !== SyntaxKind.QuestionQuestionToken) {
|
||||
return;
|
||||
}
|
||||
if (isBinaryExpression(node.parent)) {
|
||||
const { left, operatorToken } = node.parent;
|
||||
if (isBinaryExpression(left) && operatorToken.kind === SyntaxKind.BarBarToken) {
|
||||
grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(SyntaxKind.QuestionQuestionToken), tokenToString(operatorToken.kind));
|
||||
}
|
||||
}
|
||||
else if (isBinaryExpression(node.left)) {
|
||||
const { operatorToken } = node.left;
|
||||
if (operatorToken.kind === SyntaxKind.BarBarToken || operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
|
||||
grammarErrorOnNode(node.left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(operatorToken.kind), tokenToString(SyntaxKind.QuestionQuestionToken));
|
||||
}
|
||||
}
|
||||
else if (isBinaryExpression(node.right)) {
|
||||
const { operatorToken } = node.right;
|
||||
if (operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
|
||||
grammarErrorOnNode(node.right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(SyntaxKind.QuestionQuestionToken), tokenToString(operatorToken.kind));
|
||||
}
|
||||
}
|
||||
checkNullishCoalesceOperandLeft(node);
|
||||
checkNullishCoalesceOperandRight(node);
|
||||
}
|
||||
|
||||
function checkNullishCoalesceOperandLeft(node: BinaryExpression) {
|
||||
|
||||
@@ -5675,17 +5675,17 @@ export const enum OperatorPrecedence {
|
||||
// CoalesceExpression
|
||||
Conditional,
|
||||
|
||||
// LogicalORExpression:
|
||||
// LogicalANDExpression
|
||||
// LogicalORExpression `||` LogicalANDExpression
|
||||
LogicalOR,
|
||||
|
||||
// CoalesceExpression:
|
||||
// CoalesceExpressionHead `??` BitwiseORExpression
|
||||
// CoalesceExpressionHead:
|
||||
// CoalesceExpression
|
||||
// BitwiseORExpression
|
||||
Coalesce = Conditional, // NOTE: This is wrong
|
||||
|
||||
// LogicalORExpression:
|
||||
// LogicalANDExpression
|
||||
// LogicalORExpression `||` LogicalANDExpression
|
||||
LogicalOR,
|
||||
Coalesce = LogicalOR,
|
||||
|
||||
// LogicalANDExpression:
|
||||
// BitwiseORExpression
|
||||
|
||||
@@ -366,5 +366,62 @@ describe("unittests:: PrinterAPI", () => {
|
||||
ts.factory.createNoSubstitutionTemplateLiteral("\n"),
|
||||
ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext),
|
||||
));
|
||||
|
||||
printsCorrectly("binaryBarBarExpressionWithLeftConditionalExpression", {}, printer =>
|
||||
printer.printNode(
|
||||
ts.EmitHint.Unspecified,
|
||||
ts.factory.createExpressionStatement(
|
||||
ts.factory.createBinaryExpression(
|
||||
ts.factory.createConditionalExpression(
|
||||
ts.factory.createIdentifier("a"),
|
||||
ts.factory.createToken(ts.SyntaxKind.QuestionToken),
|
||||
ts.factory.createIdentifier("b"),
|
||||
ts.factory.createToken(ts.SyntaxKind.ColonToken),
|
||||
ts.factory.createIdentifier("c"),
|
||||
),
|
||||
ts.factory.createToken(ts.SyntaxKind.BarBarToken),
|
||||
ts.factory.createIdentifier("d"),
|
||||
),
|
||||
),
|
||||
ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext),
|
||||
));
|
||||
|
||||
printsCorrectly("binaryAmpersandAmpersandExpressionWithLeftConditionalExpression", {}, printer =>
|
||||
printer.printNode(
|
||||
ts.EmitHint.Unspecified,
|
||||
ts.factory.createExpressionStatement(
|
||||
ts.factory.createBinaryExpression(
|
||||
ts.factory.createConditionalExpression(
|
||||
ts.factory.createIdentifier("a"),
|
||||
ts.factory.createToken(ts.SyntaxKind.QuestionToken),
|
||||
ts.factory.createIdentifier("b"),
|
||||
ts.factory.createToken(ts.SyntaxKind.ColonToken),
|
||||
ts.factory.createIdentifier("c"),
|
||||
),
|
||||
ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
|
||||
ts.factory.createIdentifier("d"),
|
||||
),
|
||||
),
|
||||
ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext),
|
||||
));
|
||||
|
||||
printsCorrectly("binaryQuestionQuestionExpressionWithLeftConditionalExpression", {}, printer =>
|
||||
printer.printNode(
|
||||
ts.EmitHint.Unspecified,
|
||||
ts.factory.createExpressionStatement(
|
||||
ts.factory.createBinaryExpression(
|
||||
ts.factory.createConditionalExpression(
|
||||
ts.factory.createIdentifier("a"),
|
||||
ts.factory.createToken(ts.SyntaxKind.QuestionToken),
|
||||
ts.factory.createIdentifier("b"),
|
||||
ts.factory.createToken(ts.SyntaxKind.ColonToken),
|
||||
ts.factory.createIdentifier("c"),
|
||||
),
|
||||
ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
|
||||
ts.factory.createIdentifier("d"),
|
||||
),
|
||||
),
|
||||
ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext),
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user