@@ -13254,7 +13254,7 @@ namespace ts {
1325413254 return isContextSensitive((<ConditionalExpression>node).whenTrue) ||
1325513255 isContextSensitive((<ConditionalExpression>node).whenFalse);
1325613256 case SyntaxKind.BinaryExpression:
13257- return (<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken &&
13257+ return (( <BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken || (<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken) &&
1325813258 (isContextSensitive((<BinaryExpression>node).left) || isContextSensitive((<BinaryExpression>node).right));
1325913259 case SyntaxKind.PropertyAssignment:
1326013260 return isContextSensitive((<PropertyAssignment>node).initializer);
@@ -19697,7 +19697,8 @@ namespace ts {
1969719697 // will be a subtype or the same type as the argument.
1969819698 function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
1969919699 // for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a`
19700- if (isOptionalChainRoot(expr.parent)) {
19700+ if (isOptionalChainRoot(expr.parent) ||
19701+ isBinaryExpression(expr.parent) && expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken && expr.parent.left === expr) {
1970119702 return narrowTypeByOptionality(type, expr, assumeTrue);
1970219703 }
1970319704 switch (expr.kind) {
@@ -20903,6 +20904,7 @@ namespace ts {
2090320904 }
2090420905 return contextSensitive === true ? getTypeOfExpression(left) : contextSensitive;
2090520906 case SyntaxKind.BarBarToken:
20907+ case SyntaxKind.QuestionQuestionToken:
2090620908 // When an || expression has a contextual type, the operands are contextually typed by that type, except
2090720909 // when that type originates in a binding pattern, the right operand is contextually typed by the type of
2090820910 // the left operand. When an || expression has no contextual type, the right operand is contextually typed
@@ -26471,16 +26473,29 @@ namespace ts {
2647126473 if (isInJSFile(node) && getAssignedExpandoInitializer(node)) {
2647226474 return checkExpression(node.right, checkMode);
2647326475 }
26476+ checkGrammarNullishCoalesceWithLogicalExpression(node);
2647426477 return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, checkMode, node);
2647526478 }
2647626479
26480+ function checkGrammarNullishCoalesceWithLogicalExpression(node: BinaryExpression) {
26481+ const { left, operatorToken, right } = node;
26482+ if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) {
26483+ if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) {
26484+ grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind));
26485+ }
26486+ if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) {
26487+ grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind));
26488+ }
26489+ }
26490+ }
26491+
2647726492 function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type {
2647826493 const operator = operatorToken.kind;
2647926494 if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) {
2648026495 return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword);
2648126496 }
2648226497 let leftType: Type;
26483- if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) {
26498+ if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken ) {
2648426499 leftType = checkTruthinessExpression(left, checkMode);
2648526500 }
2648626501 else {
@@ -26641,6 +26656,10 @@ namespace ts {
2664126656 return getTypeFacts(leftType) & TypeFacts.Falsy ?
2664226657 getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) :
2664326658 leftType;
26659+ case SyntaxKind.QuestionQuestionToken:
26660+ return getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ?
26661+ getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) :
26662+ leftType;
2664426663 case SyntaxKind.EqualsToken:
2664526664 const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None;
2664626665 checkAssignmentDeclaration(declKind, rightType);
0 commit comments