Skip to content

Commit 9e3852e

Browse files
committed
Merge branch 'nullish-coalescing-operator' of github.com:Kingwl/TypeScript into nullish-coalescing-operator
2 parents 78df31b + 57be95d commit 9e3852e

16 files changed

+93
-24
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,7 +1460,6 @@ namespace ts {
14601460
}
14611461
}
14621462

1463-
// TODO(rbuckton): Determine how to hook ?? into flow typing
14641463
function bindBinaryExpressionFlow(node: BinaryExpression) {
14651464
const operator = node.operatorToken.kind;
14661465
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) {
@@ -2815,7 +2814,7 @@ namespace ts {
28152814
init = init && getRightMostAssignedExpression(init);
28162815
if (init) {
28172816
const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node) ? node.name : isBinaryExpression(node) ? node.left : node);
2818-
return !!getExpandoInitializer(isBinaryExpression(init) && init.operatorToken.kind === SyntaxKind.BarBarToken ? init.right : init, isPrototypeAssignment);
2817+
return !!getExpandoInitializer(isBinaryExpression(init) && (init.operatorToken.kind === SyntaxKind.BarBarToken || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, isPrototypeAssignment);
28192818
}
28202819
return false;
28212820
}

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26256,10 +26256,10 @@ namespace ts {
2625626256
const { left, operatorToken, right } = node;
2625726257
if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) {
2625826258
if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) {
26259-
error(left, Diagnostics.Operator_0_cannot_immediately_contain_or_be_contained_within_an_1_operation, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind));
26259+
grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind));
2626026260
}
2626126261
if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) {
26262-
error(right, Diagnostics.Operator_0_cannot_immediately_contain_or_be_contained_within_an_1_operation, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind));
26262+
grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind));
2626326263
}
2626426264
}
2626526265
}

src/compiler/diagnosticMessages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3229,7 +3229,7 @@
32293229
"category": "Error",
32303230
"code": 5075
32313231
},
3232-
"Operator '{0}' cannot immediately contain, or be contained within an '{1}' operation.": {
3232+
"'{0}' and '{1}' operations cannot be mixed without parentheses.": {
32333233
"category": "Error",
32343234
"code": 5076
32353235
},

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3007,7 +3007,7 @@ namespace ts {
30073007
return parseJSDocAllType(/*postfixEquals*/ true);
30083008
case SyntaxKind.QuestionQuestionToken:
30093009
// If there is '??', consider that is prefix '?' in JSDoc type.
3010-
scanner.reScanQuestionQuestionToken();
3010+
scanner.reScanQuestionToken();
30113011
// falls through
30123012
case SyntaxKind.QuestionToken:
30133013
return parseJSDocUnknownOrNullableType();

src/compiler/scanner.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace ts {
3333
scanJsxAttributeValue(): SyntaxKind;
3434
reScanJsxToken(): JsxTokenSyntaxKind;
3535
reScanLessThanToken(): SyntaxKind;
36-
reScanQuestionQuestionToken(): SyntaxKind;
36+
reScanQuestionToken(): SyntaxKind;
3737
scanJsxToken(): JsxTokenSyntaxKind;
3838
scanJsDocToken(): JSDocSyntaxKind;
3939
scan(): SyntaxKind;
@@ -903,7 +903,7 @@ namespace ts {
903903
scanJsxAttributeValue,
904904
reScanJsxToken,
905905
reScanLessThanToken,
906-
reScanQuestionQuestionToken,
906+
reScanQuestionToken,
907907
scanJsxToken,
908908
scanJsDocToken,
909909
scan,
@@ -2024,8 +2024,8 @@ namespace ts {
20242024
return token;
20252025
}
20262026

2027-
function reScanQuestionQuestionToken(): SyntaxKind {
2028-
Debug.assert(token === SyntaxKind.QuestionQuestionToken, "'reScanQuestionQuestionToken' should only be called on a '??'");
2027+
function reScanQuestionToken(): SyntaxKind {
2028+
Debug.assert(token === SyntaxKind.QuestionQuestionToken, "'reScanQuestionToken' should only be called on a '??'");
20292029
pos = tokenPos + 1;
20302030
return token = SyntaxKind.QuestionToken;
20312031
}

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,7 @@ namespace ts {
19841984
/** Given an expando initializer, return its declaration name, or the left-hand side of the assignment if it's part of an assignment declaration. */
19851985
export function getNameOfExpando(node: Declaration): DeclarationName | undefined {
19861986
if (isBinaryExpression(node.parent)) {
1987-
const parent = (node.parent.operatorToken.kind === SyntaxKind.BarBarToken && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent;
1987+
const parent = ((node.parent.operatorToken.kind === SyntaxKind.BarBarToken || node.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent;
19881988
if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) {
19891989
return parent.left;
19901990
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3236,7 +3236,7 @@ declare namespace ts {
32363236
scanJsxAttributeValue(): SyntaxKind;
32373237
reScanJsxToken(): JsxTokenSyntaxKind;
32383238
reScanLessThanToken(): SyntaxKind;
3239-
reScanQuestionQuestionToken(): SyntaxKind;
3239+
reScanQuestionToken(): SyntaxKind;
32403240
scanJsxToken(): JsxTokenSyntaxKind;
32413241
scanJsDocToken(): JSDocSyntaxKind;
32423242
scan(): SyntaxKind;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3236,7 +3236,7 @@ declare namespace ts {
32363236
scanJsxAttributeValue(): SyntaxKind;
32373237
reScanJsxToken(): JsxTokenSyntaxKind;
32383238
reScanLessThanToken(): SyntaxKind;
3239-
reScanQuestionQuestionToken(): SyntaxKind;
3239+
reScanQuestionToken(): SyntaxKind;
32403240
scanJsxToken(): JsxTokenSyntaxKind;
32413241
scanJsDocToken(): JSDocSyntaxKind;
32423242
scan(): SyntaxKind;

tests/baselines/reference/nullishCoalescingOperator3.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ const aa1 = a1 ?? a2 ?? a3 ?? a4 ?? a5 ?? a6 ?? 'whatever'
1111

1212

1313
//// [nullishCoalescingOperator3.js]
14-
var _a, _b, _c, _d, _e;
1514
"use strict";
15+
var _a, _b, _c, _d, _e;
1616
var aa1 = (_e = (_d = (_c = (_b = (_a = (a1 != null ? a1 : a2), (_a != null ? _a : a3)), (_b != null ? _b : a4)), (_c != null ? _c : a5)), (_d != null ? _d : a6)), (_e != null ? _e : 'whatever'));

tests/baselines/reference/nullishCoalescingOperator5.errors.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(6,6): error TS5076: Operator '||' cannot immediately contain, or be contained within an '??' operation.
2-
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(9,1): error TS5076: Operator '||' cannot immediately contain, or be contained within an '??' operation.
3-
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(12,6): error TS5076: Operator '&&' cannot immediately contain, or be contained within an '??' operation.
4-
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(15,1): error TS5076: Operator '&&' cannot immediately contain, or be contained within an '??' operation.
1+
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(6,6): error TS5076: '||' and '??' operations cannot be mixed without parentheses.
2+
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(9,1): error TS5076: '||' and '??' operations cannot be mixed without parentheses.
3+
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(12,6): error TS5076: '&&' and '??' operations cannot be mixed without parentheses.
4+
tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts(15,1): error TS5076: '&&' and '??' operations cannot be mixed without parentheses.
55

66

77
==== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator5.ts (4 errors) ====
@@ -12,22 +12,22 @@ tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingO
1212
// should be a syntax error
1313
a ?? b || c;
1414
~~~~~~
15-
!!! error TS5076: Operator '||' cannot immediately contain, or be contained within an '??' operation.
15+
!!! error TS5076: '||' and '??' operations cannot be mixed without parentheses.
1616

1717
// should be a syntax error
1818
a || b ?? c;
1919
~~~~~~
20-
!!! error TS5076: Operator '||' cannot immediately contain, or be contained within an '??' operation.
20+
!!! error TS5076: '||' and '??' operations cannot be mixed without parentheses.
2121

2222
// should be a syntax error
2323
a ?? b && c;
2424
~~~~~~
25-
!!! error TS5076: Operator '&&' cannot immediately contain, or be contained within an '??' operation.
25+
!!! error TS5076: '&&' and '??' operations cannot be mixed without parentheses.
2626

2727
// should be a syntax error
2828
a && b ?? c;
2929
~~~~~~
30-
!!! error TS5076: Operator '&&' cannot immediately contain, or be contained within an '??' operation.
30+
!!! error TS5076: '&&' and '??' operations cannot be mixed without parentheses.
3131

3232
// Valid according to spec
3333
a ?? (b || c);

tests/baselines/reference/nullishCoalescingOperator5.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ a && (b ?? c);
4141

4242

4343
//// [nullishCoalescingOperator5.js]
44-
var _a, _b, _c, _d;
4544
"use strict";
45+
var _a, _b, _c, _d;
4646
// should be a syntax error
4747
(a != null ? a : b || c);
4848
// should be a syntax error

tests/baselines/reference/nullishCoalescingOperator8.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const n3 = a.m() ?? b.p ?? b.m() ?? "default";;
88

99

1010
//// [nullishCoalescingOperator8.js]
11-
var _a, _b, _c, _d, _e;
1211
"use strict";
12+
var _a, _b, _c, _d, _e;
1313
var n1 = (_a = a.p, (_a != null ? _a : "default"));
1414
var n2 = (_b = a.m(), (_b != null ? _b : "default"));
1515
var n3 = (_e = (_d = (_c = a.m(), (_c != null ? _c : b.p)), (_d != null ? _d : b.m())), (_e != null ? _e : "default"));
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [nullishCoalescingOperator9.ts]
2+
declare let f: null | ((x: string) => void);
3+
4+
let g = f || (abc => { void abc.toLowerCase() })
5+
let gg = f ?? (abc => { void abc.toLowerCase() })
6+
7+
8+
//// [nullishCoalescingOperator9.js]
9+
"use strict";
10+
var g = f || (function (abc) { void abc.toLowerCase(); });
11+
var gg = (f != null ? f : (function (abc) { void abc.toLowerCase(); }));
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator9.ts ===
2+
declare let f: null | ((x: string) => void);
3+
>f : Symbol(f, Decl(nullishCoalescingOperator9.ts, 0, 11))
4+
>x : Symbol(x, Decl(nullishCoalescingOperator9.ts, 0, 24))
5+
6+
let g = f || (abc => { void abc.toLowerCase() })
7+
>g : Symbol(g, Decl(nullishCoalescingOperator9.ts, 2, 3))
8+
>f : Symbol(f, Decl(nullishCoalescingOperator9.ts, 0, 11))
9+
>abc : Symbol(abc, Decl(nullishCoalescingOperator9.ts, 2, 14))
10+
>abc.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
11+
>abc : Symbol(abc, Decl(nullishCoalescingOperator9.ts, 2, 14))
12+
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
13+
14+
let gg = f ?? (abc => { void abc.toLowerCase() })
15+
>gg : Symbol(gg, Decl(nullishCoalescingOperator9.ts, 3, 3))
16+
>f : Symbol(f, Decl(nullishCoalescingOperator9.ts, 0, 11))
17+
>abc : Symbol(abc, Decl(nullishCoalescingOperator9.ts, 3, 15))
18+
>abc.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
19+
>abc : Symbol(abc, Decl(nullishCoalescingOperator9.ts, 3, 15))
20+
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
21+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator9.ts ===
2+
declare let f: null | ((x: string) => void);
3+
>f : ((x: string) => void) | null
4+
>null : null
5+
>x : string
6+
7+
let g = f || (abc => { void abc.toLowerCase() })
8+
>g : (x: string) => void
9+
>f || (abc => { void abc.toLowerCase() }) : (x: string) => void
10+
>f : ((x: string) => void) | null
11+
>(abc => { void abc.toLowerCase() }) : (abc: string) => void
12+
>abc => { void abc.toLowerCase() } : (abc: string) => void
13+
>abc : string
14+
>void abc.toLowerCase() : undefined
15+
>abc.toLowerCase() : string
16+
>abc.toLowerCase : () => string
17+
>abc : string
18+
>toLowerCase : () => string
19+
20+
let gg = f ?? (abc => { void abc.toLowerCase() })
21+
>gg : (x: string) => void
22+
>f ?? (abc => { void abc.toLowerCase() }) : (x: string) => void
23+
>f : ((x: string) => void) | null
24+
>(abc => { void abc.toLowerCase() }) : (abc: string) => void
25+
>abc => { void abc.toLowerCase() } : (abc: string) => void
26+
>abc : string
27+
>void abc.toLowerCase() : undefined
28+
>abc.toLowerCase() : string
29+
>abc.toLowerCase : () => string
30+
>abc : string
31+
>toLowerCase : () => string
32+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @strict: true
2+
3+
declare let f: null | ((x: string) => void);
4+
5+
let g = f || (abc => { void abc.toLowerCase() })
6+
let gg = f ?? (abc => { void abc.toLowerCase() })

0 commit comments

Comments
 (0)