mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Initial support for coalesce
This commit is contained in:
@@ -857,7 +857,8 @@ namespace ts {
|
||||
else {
|
||||
return node.kind === SyntaxKind.BinaryExpression && (
|
||||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken ||
|
||||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken);
|
||||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken ||
|
||||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1256,9 +1257,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(rbuckton): Determine how to hook ?? into flow typing
|
||||
function bindBinaryExpressionFlow(node: BinaryExpression) {
|
||||
const operator = node.operatorToken.kind;
|
||||
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) {
|
||||
if (operator === SyntaxKind.AmpersandAmpersandToken ||
|
||||
operator === SyntaxKind.BarBarToken) {
|
||||
if (isTopLevelLogicalExpression(node)) {
|
||||
const postExpressionLabel = createBranchLabel();
|
||||
bindLogicalExpression(node, postExpressionLabel, postExpressionLabel);
|
||||
@@ -2737,7 +2740,10 @@ namespace ts {
|
||||
const operatorTokenKind = node.operatorToken.kind;
|
||||
const leftKind = node.left.kind;
|
||||
|
||||
if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (operatorTokenKind === SyntaxKind.QuestionQuestionToken) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
else if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) {
|
||||
// Destructuring object assignments with are ES2015 syntax
|
||||
// and possibly ESNext if they contain rest
|
||||
transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment;
|
||||
|
||||
@@ -8385,7 +8385,8 @@ namespace ts {
|
||||
return isContextSensitive((<ConditionalExpression>node).whenTrue) ||
|
||||
isContextSensitive((<ConditionalExpression>node).whenFalse);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return (<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken &&
|
||||
return ((<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken ||
|
||||
(<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken) &&
|
||||
(isContextSensitive((<BinaryExpression>node).left) || isContextSensitive((<BinaryExpression>node).right));
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return isContextSensitive((<PropertyAssignment>node).initializer);
|
||||
@@ -13301,7 +13302,7 @@ namespace ts {
|
||||
return getTypeOfExpression(binaryExpression.left);
|
||||
}
|
||||
}
|
||||
else if (operator === SyntaxKind.BarBarToken) {
|
||||
else if (operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) {
|
||||
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
|
||||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand.
|
||||
let type = getContextualType(binaryExpression);
|
||||
@@ -17989,6 +17990,10 @@ namespace ts {
|
||||
return getTypeFacts(leftType) & TypeFacts.Falsy ?
|
||||
getBestChoiceType(removeDefinitelyFalsyTypes(leftType), rightType) :
|
||||
leftType;
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
return getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ?
|
||||
getBestChoiceType(getNonNullableType(leftType), rightType) :
|
||||
leftType;
|
||||
case SyntaxKind.EqualsToken:
|
||||
checkAssignmentOperator(rightType);
|
||||
return getRegularTypeOfObjectLiteral(rightType);
|
||||
|
||||
@@ -3549,6 +3549,7 @@ namespace ts {
|
||||
|
||||
function getBinaryOperatorPrecedence(): number {
|
||||
switch (token()) {
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
case SyntaxKind.BarBarToken:
|
||||
return 1;
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
@@ -4310,6 +4311,7 @@ namespace ts {
|
||||
case SyntaxKind.ColonToken: // foo<x>:
|
||||
case SyntaxKind.SemicolonToken: // foo<x>;
|
||||
case SyntaxKind.QuestionToken: // foo<x>?
|
||||
case SyntaxKind.QuestionQuestionToken: // foo<x> ??
|
||||
case SyntaxKind.EqualsEqualsToken: // foo<x> ==
|
||||
case SyntaxKind.EqualsEqualsEqualsToken: // foo<x> ===
|
||||
case SyntaxKind.ExclamationEqualsToken: // foo<x> !=
|
||||
|
||||
@@ -169,6 +169,7 @@ namespace ts {
|
||||
"&&": SyntaxKind.AmpersandAmpersandToken,
|
||||
"||": SyntaxKind.BarBarToken,
|
||||
"?": SyntaxKind.QuestionToken,
|
||||
"??": SyntaxKind.QuestionQuestionToken,
|
||||
":": SyntaxKind.ColonToken,
|
||||
"=": SyntaxKind.EqualsToken,
|
||||
"+=": SyntaxKind.PlusEqualsToken,
|
||||
@@ -1553,6 +1554,9 @@ namespace ts {
|
||||
pos++;
|
||||
return token = SyntaxKind.GreaterThanToken;
|
||||
case CharacterCodes.question:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.question) {
|
||||
return pos += 2, token = SyntaxKind.QuestionQuestionToken;
|
||||
}
|
||||
pos++;
|
||||
return token = SyntaxKind.QuestionToken;
|
||||
case CharacterCodes.openBracket:
|
||||
|
||||
@@ -225,6 +225,34 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function createNotUndefinedCondition(node: Expression) {
|
||||
return isIdentifier(node) && !isGeneratedIdentifier(node)
|
||||
? createStrictInequality(createTypeOf(node), createLiteral("undefined"))
|
||||
: createStrictInequality(node, createVoidZero());
|
||||
}
|
||||
|
||||
function createNotNullCondition(node: Expression) {
|
||||
return createStrictInequality(node, createNull());
|
||||
}
|
||||
|
||||
function transformCoalesceExpression(node: BinaryExpression) {
|
||||
const expressions: Expression[] = [];
|
||||
let left = visitNode(node.left, visitor, isExpression);
|
||||
if (!isIdentifier(left)) {
|
||||
const temp = createTempVariable(hoistVariableDeclaration);
|
||||
expressions.push(createAssignment(temp, left));
|
||||
left = temp;
|
||||
}
|
||||
expressions.push(
|
||||
createConditional(
|
||||
createLogicalAnd(
|
||||
createNotUndefinedCondition(left),
|
||||
createNotNullCondition(left)),
|
||||
left,
|
||||
visitNode(node.right, visitor, isExpression)));
|
||||
return inlineExpressions(expressions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a BinaryExpression that contains a destructuring assignment.
|
||||
*
|
||||
@@ -240,6 +268,9 @@ namespace ts {
|
||||
!noDestructuringValue
|
||||
);
|
||||
}
|
||||
else if (node.operatorToken.kind === SyntaxKind.QuestionQuestionToken) {
|
||||
return transformCoalesceExpression(node);
|
||||
}
|
||||
else if (node.operatorToken.kind === SyntaxKind.CommaToken) {
|
||||
return updateBinary(
|
||||
node,
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace ts {
|
||||
AmpersandAmpersandToken,
|
||||
BarBarToken,
|
||||
QuestionToken,
|
||||
QuestionQuestionToken,
|
||||
ColonToken,
|
||||
AtToken,
|
||||
// Assignments
|
||||
@@ -1270,6 +1271,7 @@ namespace ts {
|
||||
export type LogicalOperator
|
||||
= SyntaxKind.AmpersandAmpersandToken
|
||||
| SyntaxKind.BarBarToken
|
||||
| SyntaxKind.QuestionQuestionToken
|
||||
;
|
||||
|
||||
// see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression
|
||||
|
||||
@@ -2225,6 +2225,7 @@ namespace ts {
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
return 6;
|
||||
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
case SyntaxKind.BarBarToken:
|
||||
return 5;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user