mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #37727 from Kingwl/logical_assignment
Add logical assignment operator
This commit is contained in:
+30
-7
@@ -905,6 +905,9 @@ namespace ts {
|
||||
function isNarrowingBinaryExpression(expr: BinaryExpression) {
|
||||
switch (expr.operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
return containsNarrowableReference(expr.left);
|
||||
case SyntaxKind.EqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsToken:
|
||||
@@ -1041,12 +1044,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isLogicalAssignmentExpression(node: Node) {
|
||||
node = skipParentheses(node);
|
||||
return isBinaryExpression(node) && isLogicalOrCoalescingAssignmentOperator(node.operatorToken.kind);
|
||||
}
|
||||
|
||||
function isTopLevelLogicalExpression(node: Node): boolean {
|
||||
while (isParenthesizedExpression(node.parent) ||
|
||||
isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken) {
|
||||
node = node.parent;
|
||||
}
|
||||
return !isStatementCondition(node) &&
|
||||
!isLogicalAssignmentExpression(node.parent) &&
|
||||
!isLogicalExpression(node.parent) &&
|
||||
!(isOptionalChain(node.parent) && node.parent.expression === node);
|
||||
}
|
||||
@@ -1063,7 +1072,7 @@ namespace ts {
|
||||
|
||||
function bindCondition(node: Expression | undefined, trueTarget: FlowLabel, falseTarget: FlowLabel) {
|
||||
doWithConditionalBranches(bind, node, trueTarget, falseTarget);
|
||||
if (!node || !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) {
|
||||
if (!node || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) {
|
||||
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
|
||||
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
|
||||
}
|
||||
@@ -1404,9 +1413,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function bindLogicalExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
|
||||
function bindLogicalLikeExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
|
||||
const preRightLabel = createBranchLabel();
|
||||
if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) {
|
||||
if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken) {
|
||||
bindCondition(node.left, preRightLabel, falseTarget);
|
||||
}
|
||||
else {
|
||||
@@ -1414,7 +1423,17 @@ namespace ts {
|
||||
}
|
||||
currentFlow = finishFlowLabel(preRightLabel);
|
||||
bind(node.operatorToken);
|
||||
bindCondition(node.right, trueTarget, falseTarget);
|
||||
|
||||
if (isLogicalOrCoalescingAssignmentOperator(node.operatorToken.kind)) {
|
||||
doWithConditionalBranches(bind, node.right, trueTarget, falseTarget);
|
||||
bindAssignmentTargetFlow(node.left);
|
||||
|
||||
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
|
||||
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
|
||||
}
|
||||
else {
|
||||
bindCondition(node.right, trueTarget, falseTarget);
|
||||
}
|
||||
}
|
||||
|
||||
function bindPrefixUnaryExpressionFlow(node: PrefixUnaryExpression) {
|
||||
@@ -1500,14 +1519,15 @@ namespace ts {
|
||||
// TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions
|
||||
// we'll need to handle the `bindLogicalExpression` scenarios in this state machine, too
|
||||
// For now, though, since the common cases are chained `+`, leaving it recursive is fine
|
||||
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) {
|
||||
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken ||
|
||||
isLogicalOrCoalescingAssignmentOperator(operator)) {
|
||||
if (isTopLevelLogicalExpression(node)) {
|
||||
const postExpressionLabel = createBranchLabel();
|
||||
bindLogicalExpression(node, postExpressionLabel, postExpressionLabel);
|
||||
bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel);
|
||||
currentFlow = finishFlowLabel(postExpressionLabel);
|
||||
}
|
||||
else {
|
||||
bindLogicalExpression(node, currentTrueTarget!, currentFalseTarget!);
|
||||
bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!);
|
||||
}
|
||||
completeNode();
|
||||
}
|
||||
@@ -3607,6 +3627,9 @@ namespace ts {
|
||||
if (operatorTokenKind === SyntaxKind.QuestionQuestionToken) {
|
||||
transformFlags |= TransformFlags.AssertES2020;
|
||||
}
|
||||
else if (isLogicalOrCoalescingAssignmentOperator(operatorTokenKind)) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
else if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) {
|
||||
// Destructuring object assignments with are ES2015 syntax
|
||||
// and possibly ES2018 if they contain rest
|
||||
|
||||
+30
-3
@@ -19864,6 +19864,9 @@ namespace ts {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
switch ((<BinaryExpression>node).operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
return getReferenceCandidate((<BinaryExpression>node).left);
|
||||
case SyntaxKind.CommaToken:
|
||||
return getReferenceCandidate((<BinaryExpression>node).right);
|
||||
@@ -20838,6 +20841,9 @@ namespace ts {
|
||||
function narrowTypeByBinaryExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
|
||||
switch (expr.operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
return narrowTypeByTruthiness(narrowType(type, expr.right, assumeTrue), expr.left, assumeTrue);
|
||||
case SyntaxKind.EqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsToken:
|
||||
@@ -22462,6 +22468,9 @@ namespace ts {
|
||||
const { left, operatorToken, right } = binaryExpression;
|
||||
switch (operatorToken.kind) {
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
if (node !== right) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -28758,17 +28767,35 @@ namespace ts {
|
||||
case SyntaxKind.InKeyword:
|
||||
return checkInExpression(left, right, leftType, rightType);
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
return getTypeFacts(leftType) & TypeFacts.Truthy ?
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken: {
|
||||
const resultType = getTypeFacts(leftType) & TypeFacts.Truthy ?
|
||||
getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) :
|
||||
leftType;
|
||||
if (operator === SyntaxKind.AmpersandAmpersandEqualsToken) {
|
||||
checkAssignmentOperator(rightType);
|
||||
}
|
||||
return resultType;
|
||||
}
|
||||
case SyntaxKind.BarBarToken:
|
||||
return getTypeFacts(leftType) & TypeFacts.Falsy ?
|
||||
case SyntaxKind.BarBarEqualsToken: {
|
||||
const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ?
|
||||
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
if (operator === SyntaxKind.BarBarEqualsToken) {
|
||||
checkAssignmentOperator(rightType);
|
||||
}
|
||||
return resultType;
|
||||
}
|
||||
case SyntaxKind.QuestionQuestionToken:
|
||||
return getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ?
|
||||
case SyntaxKind.QuestionQuestionEqualsToken: {
|
||||
const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ?
|
||||
getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
if (operator === SyntaxKind.QuestionQuestionEqualsToken) {
|
||||
checkAssignmentOperator(rightType);
|
||||
}
|
||||
return resultType;
|
||||
}
|
||||
case SyntaxKind.EqualsToken:
|
||||
const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None;
|
||||
checkAssignmentDeclaration(declKind, rightType);
|
||||
|
||||
+18
-8
@@ -208,6 +208,9 @@ namespace ts {
|
||||
"&=": SyntaxKind.AmpersandEqualsToken,
|
||||
"|=": SyntaxKind.BarEqualsToken,
|
||||
"^=": SyntaxKind.CaretEqualsToken,
|
||||
"||=": SyntaxKind.BarBarEqualsToken,
|
||||
"&&=": SyntaxKind.AmpersandAmpersandEqualsToken,
|
||||
"??=": SyntaxKind.QuestionQuestionEqualsToken,
|
||||
"@": SyntaxKind.AtToken,
|
||||
"`": SyntaxKind.BacktickToken
|
||||
});
|
||||
@@ -1667,6 +1670,9 @@ namespace ts {
|
||||
return token = SyntaxKind.PercentToken;
|
||||
case CharacterCodes.ampersand:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.ampersand) {
|
||||
if (text.charCodeAt(pos + 2) === CharacterCodes.equals) {
|
||||
return pos += 3, token = SyntaxKind.AmpersandAmpersandEqualsToken;
|
||||
}
|
||||
return pos += 2, token = SyntaxKind.AmpersandAmpersandToken;
|
||||
}
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
@@ -1928,15 +1934,16 @@ namespace ts {
|
||||
pos++;
|
||||
return token = SyntaxKind.GreaterThanToken;
|
||||
case CharacterCodes.question:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.dot && !isDigit(text.charCodeAt(pos + 2))) {
|
||||
return pos += 2, token = SyntaxKind.QuestionDotToken;
|
||||
}
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.question) {
|
||||
if (text.charCodeAt(pos + 2) === CharacterCodes.equals) {
|
||||
return pos += 3, token = SyntaxKind.QuestionQuestionEqualsToken;
|
||||
}
|
||||
return pos += 2, token = SyntaxKind.QuestionQuestionToken;
|
||||
}
|
||||
pos++;
|
||||
if (text.charCodeAt(pos) === CharacterCodes.dot && !isDigit(text.charCodeAt(pos + 1))) {
|
||||
pos++;
|
||||
return token = SyntaxKind.QuestionDotToken;
|
||||
}
|
||||
if (text.charCodeAt(pos) === CharacterCodes.question) {
|
||||
pos++;
|
||||
return token = SyntaxKind.QuestionQuestionToken;
|
||||
}
|
||||
return token = SyntaxKind.QuestionToken;
|
||||
case CharacterCodes.openBracket:
|
||||
pos++;
|
||||
@@ -1965,6 +1972,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.bar) {
|
||||
if (text.charCodeAt(pos + 2) === CharacterCodes.equals) {
|
||||
return pos += 3, token = SyntaxKind.BarBarEqualsToken;
|
||||
}
|
||||
return pos += 2, token = SyntaxKind.BarBarToken;
|
||||
}
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace ts {
|
||||
|
||||
let thisArg: Expression | undefined;
|
||||
if (captureThisArg) {
|
||||
if (shouldCaptureInTempVariable(expression)) {
|
||||
if (!isSimpleCopiableExpression(expression)) {
|
||||
thisArg = createTempVariable(hoistVariableDeclaration);
|
||||
expression = createAssignment(thisArg, expression);
|
||||
// if (inParameterInitializer) tempVariableInParameter = true;
|
||||
@@ -113,7 +113,7 @@ namespace ts {
|
||||
const leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
|
||||
let leftExpression = isSyntheticReference(left) ? left.expression : left;
|
||||
let capturedLeft: Expression = leftExpression;
|
||||
if (shouldCaptureInTempVariable(leftExpression)) {
|
||||
if (!isSimpleCopiableExpression(leftExpression)) {
|
||||
capturedLeft = createTempVariable(hoistVariableDeclaration);
|
||||
leftExpression = createAssignment(capturedLeft, leftExpression);
|
||||
// if (inParameterInitializer) tempVariableInParameter = true;
|
||||
@@ -126,7 +126,7 @@ namespace ts {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (i === chain.length - 1 && captureThisArg) {
|
||||
if (shouldCaptureInTempVariable(rightExpression)) {
|
||||
if (!isSimpleCopiableExpression(rightExpression)) {
|
||||
thisArg = createTempVariable(hoistVariableDeclaration);
|
||||
rightExpression = createAssignment(thisArg, rightExpression);
|
||||
// if (inParameterInitializer) tempVariableInParameter = true;
|
||||
@@ -184,7 +184,7 @@ namespace ts {
|
||||
function transformNullishCoalescingExpression(node: BinaryExpression) {
|
||||
let left = visitNode(node.left, visitor, isExpression);
|
||||
let right = left;
|
||||
if (shouldCaptureInTempVariable(left)) {
|
||||
if (!isSimpleCopiableExpression(left)) {
|
||||
right = createTempVariable(hoistVariableDeclaration);
|
||||
left = createAssignment(right, left);
|
||||
// if (inParameterInitializer) tempVariableInParameter = true;
|
||||
@@ -196,14 +196,6 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function shouldCaptureInTempVariable(expression: Expression): boolean {
|
||||
// don't capture identifiers and `this` in a temporary variable
|
||||
// `super` cannot be captured as it's no real variable
|
||||
return !isIdentifier(expression) &&
|
||||
expression.kind !== SyntaxKind.ThisKeyword &&
|
||||
expression.kind !== SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
function visitDeleteExpression(node: DeleteExpression) {
|
||||
return isOptionalChain(skipParentheses(node.expression))
|
||||
? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformESNext(context: TransformationContext) {
|
||||
const {
|
||||
hoistVariableDeclaration
|
||||
} = context;
|
||||
return chainBundle(transformSourceFile);
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
@@ -16,9 +19,63 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const binaryExpression = <BinaryExpression>node;
|
||||
if (isLogicalOrCoalescingAssignmentExpression(binaryExpression)) {
|
||||
return transformLogicalAssignment(binaryExpression);
|
||||
}
|
||||
// falls through
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function transformLogicalAssignment(binaryExpression: AssignmentExpression<Token<LogicalOrCoalescingAssignmentOperator>>): VisitResult<Node> {
|
||||
const operator = binaryExpression.operatorToken;
|
||||
const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind);
|
||||
let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression));
|
||||
let assignmentTarget = left;
|
||||
const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression));
|
||||
if (isAccessExpression(left)) {
|
||||
const tempVariable = createTempVariable(hoistVariableDeclaration);
|
||||
if (isPropertyAccessExpression(left)) {
|
||||
assignmentTarget = createPropertyAccess(
|
||||
tempVariable,
|
||||
left.name
|
||||
);
|
||||
left = createPropertyAccess(
|
||||
createAssignment(
|
||||
tempVariable,
|
||||
left.expression
|
||||
),
|
||||
left.name
|
||||
);
|
||||
}
|
||||
else {
|
||||
assignmentTarget = createElementAccess(
|
||||
tempVariable,
|
||||
left.argumentExpression
|
||||
);
|
||||
left = createElementAccess(
|
||||
createAssignment(
|
||||
tempVariable,
|
||||
left.expression
|
||||
),
|
||||
left.argumentExpression
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return createBinary(
|
||||
left,
|
||||
nonAssignmentOperator,
|
||||
createParen(
|
||||
createAssignment(
|
||||
assignmentTarget,
|
||||
right
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ namespace ts {
|
||||
&& kind <= SyntaxKind.LastCompoundAssignment;
|
||||
}
|
||||
|
||||
export function getNonAssignmentOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): BitwiseOperatorOrHigher {
|
||||
export function getNonAssignmentOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): LogicalOperatorOrHigher | SyntaxKind.QuestionQuestionToken {
|
||||
switch (kind) {
|
||||
case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken;
|
||||
case SyntaxKind.MinusEqualsToken: return SyntaxKind.MinusToken;
|
||||
@@ -273,6 +273,10 @@ namespace ts {
|
||||
case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AmpersandToken;
|
||||
case SyntaxKind.BarEqualsToken: return SyntaxKind.BarToken;
|
||||
case SyntaxKind.CaretEqualsToken: return SyntaxKind.CaretToken;
|
||||
case SyntaxKind.BarBarEqualsToken: return SyntaxKind.BarBarToken;
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken: return SyntaxKind.AmpersandAmpersandToken;
|
||||
case SyntaxKind.QuestionQuestionEqualsToken: return SyntaxKind.QuestionQuestionToken;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -203,6 +203,9 @@ namespace ts {
|
||||
GreaterThanGreaterThanGreaterThanEqualsToken,
|
||||
AmpersandEqualsToken,
|
||||
BarEqualsToken,
|
||||
BarBarEqualsToken,
|
||||
AmpersandAmpersandEqualsToken,
|
||||
QuestionQuestionEqualsToken,
|
||||
CaretEqualsToken,
|
||||
// Identifiers and PrivateIdentifiers
|
||||
Identifier,
|
||||
@@ -1608,6 +1611,9 @@ namespace ts {
|
||||
| SyntaxKind.LessThanLessThanEqualsToken
|
||||
| SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken
|
||||
| SyntaxKind.GreaterThanGreaterThanEqualsToken
|
||||
| SyntaxKind.BarBarEqualsToken
|
||||
| SyntaxKind.AmpersandAmpersandEqualsToken
|
||||
| SyntaxKind.QuestionQuestionEqualsToken
|
||||
;
|
||||
|
||||
// see: https://tc39.github.io/ecma262/#prod-AssignmentExpression
|
||||
@@ -1629,6 +1635,12 @@ namespace ts {
|
||||
| SyntaxKind.CommaToken
|
||||
;
|
||||
|
||||
export type LogicalOrCoalescingAssignmentOperator
|
||||
= SyntaxKind.AmpersandAmpersandEqualsToken
|
||||
| SyntaxKind.BarBarEqualsToken
|
||||
| SyntaxKind.QuestionQuestionEqualsToken
|
||||
;
|
||||
|
||||
export type BinaryOperatorToken = Token<BinaryOperator>;
|
||||
|
||||
export interface BinaryExpression extends Expression, Declaration {
|
||||
|
||||
@@ -2594,7 +2594,7 @@ namespace ts {
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const binaryOperator = (<BinaryExpression>parent).operatorToken.kind;
|
||||
return isAssignmentOperator(binaryOperator) && (<BinaryExpression>parent).left === node ?
|
||||
return isAssignmentOperator(binaryOperator) && !isLogicalOrCoalescingAssignmentOperator(binaryOperator) && (<BinaryExpression>parent).left === node ?
|
||||
binaryOperator === SyntaxKind.EqualsToken ? AssignmentKind.Definite : AssignmentKind.Compound :
|
||||
AssignmentKind.None;
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
@@ -3226,6 +3226,9 @@ namespace ts {
|
||||
case SyntaxKind.AmpersandEqualsToken:
|
||||
case SyntaxKind.CaretEqualsToken:
|
||||
case SyntaxKind.BarEqualsToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
return Associativity.Right;
|
||||
}
|
||||
}
|
||||
@@ -3282,6 +3285,9 @@ namespace ts {
|
||||
case SyntaxKind.AmpersandEqualsToken:
|
||||
case SyntaxKind.CaretEqualsToken:
|
||||
case SyntaxKind.BarEqualsToken:
|
||||
case SyntaxKind.BarBarEqualsToken:
|
||||
case SyntaxKind.AmpersandAmpersandEqualsToken:
|
||||
case SyntaxKind.QuestionQuestionEqualsToken:
|
||||
return 3;
|
||||
|
||||
default:
|
||||
@@ -4454,6 +4460,16 @@ namespace ts {
|
||||
|| token === SyntaxKind.ExclamationToken;
|
||||
}
|
||||
|
||||
export function isLogicalOrCoalescingAssignmentOperator(token: SyntaxKind): token is LogicalOrCoalescingAssignmentOperator {
|
||||
return token === SyntaxKind.BarBarEqualsToken
|
||||
|| token === SyntaxKind.AmpersandAmpersandEqualsToken
|
||||
|| token === SyntaxKind.QuestionQuestionEqualsToken;
|
||||
}
|
||||
|
||||
export function isLogicalOrCoalescingAssignmentExpression(expr: BinaryExpression): expr is AssignmentExpression<Token<LogicalOrCoalescingAssignmentOperator>> {
|
||||
return isLogicalOrCoalescingAssignmentOperator(expr.operatorToken.kind);
|
||||
}
|
||||
|
||||
export function isAssignmentOperator(token: SyntaxKind): boolean {
|
||||
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user