Initial support for coalesce

This commit is contained in:
Ron Buckton
2017-10-06 13:18:16 -07:00
parent afa4842b2a
commit 029fbfc7e0
7 changed files with 56 additions and 5 deletions
+9 -3
View File
@@ -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;
+7 -2
View File
@@ -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);
+2
View File
@@ -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> !=
+4
View File
@@ -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:
+31
View File
@@ -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,
+2
View File
@@ -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
+1
View File
@@ -2225,6 +2225,7 @@ namespace ts {
case SyntaxKind.AmpersandAmpersandToken:
return 6;
case SyntaxKind.QuestionQuestionToken:
case SyntaxKind.BarBarToken:
return 5;