Skip to content

Commit c09e2ab

Browse files
authored
Fixed syntactic nullisness semantics for comma expressions (#60402)
1 parent 0ec4d30 commit c09e2ab

File tree

6 files changed

+152
-5
lines changed

6 files changed

+152
-5
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39772,6 +39772,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3977239772
case SyntaxKind.AmpersandAmpersandToken:
3977339773
case SyntaxKind.AmpersandAmpersandEqualsToken:
3977439774
return PredicateSemantics.Sometimes;
39775+
case SyntaxKind.CommaToken:
39776+
return getSyntacticNullishnessSemantics((node as BinaryExpression).right);
3977539777
}
3977639778
return PredicateSemantics.Never;
3977739779
case SyntaxKind.ConditionalExpression:

tests/baselines/reference/predicateSemantics.errors.txt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ predicateSemantics.ts(33,8): error TS2872: This kind of expression is always tru
99
predicateSemantics.ts(34,11): error TS2872: This kind of expression is always truthy.
1010
predicateSemantics.ts(35,8): error TS2872: This kind of expression is always truthy.
1111
predicateSemantics.ts(36,8): error TS2872: This kind of expression is always truthy.
12+
predicateSemantics.ts(51,14): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
13+
predicateSemantics.ts(52,14): error TS2695: Left side of comma operator is unused and has no side effects.
14+
predicateSemantics.ts(52,14): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
1215

1316

14-
==== predicateSemantics.ts (11 errors) ====
17+
==== predicateSemantics.ts (14 errors) ====
1518
declare let cond: any;
1619

1720
// OK: One or other operand is possibly nullish
@@ -77,4 +80,20 @@ predicateSemantics.ts(36,8): error TS2872: This kind of expression is always tru
7780
function foo(this: Object | undefined) {
7881
// Should be OK
7982
return this ?? 0;
80-
}
83+
}
84+
85+
// https://github.com/microsoft/TypeScript/issues/60401
86+
{
87+
const maybe = null as true | null;
88+
let i = 0;
89+
const d = (i++, maybe) ?? true; // ok
90+
const e = (i++, i++) ?? true; // error
91+
~~~~~~~~
92+
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
93+
const f = (maybe, i++) ?? true; // error
94+
~~~~~
95+
!!! error TS2695: Left side of comma operator is unused and has no side effects.
96+
~~~~~~~~~~
97+
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
98+
}
99+

tests/baselines/reference/predicateSemantics.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,20 @@ console.log((cond || undefined) && 1 / cond);
4444
function foo(this: Object | undefined) {
4545
// Should be OK
4646
return this ?? 0;
47-
}
47+
}
48+
49+
// https://github.com/microsoft/TypeScript/issues/60401
50+
{
51+
const maybe = null as true | null;
52+
let i = 0;
53+
const d = (i++, maybe) ?? true; // ok
54+
const e = (i++, i++) ?? true; // error
55+
const f = (maybe, i++) ?? true; // error
56+
}
57+
4858

4959
//// [predicateSemantics.js]
50-
var _a, _b, _c, _d, _e, _f;
60+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
5161
// OK: One or other operand is possibly nullish
5262
var test1 = (_a = (cond ? undefined : 32)) !== null && _a !== void 0 ? _a : "possibly reached";
5363
// Not OK: Both operands nullish
@@ -88,3 +98,11 @@ function foo() {
8898
// Should be OK
8999
return this !== null && this !== void 0 ? this : 0;
90100
}
101+
// https://github.com/microsoft/TypeScript/issues/60401
102+
{
103+
var maybe = null;
104+
var i = 0;
105+
var d = (_g = (i++, maybe)) !== null && _g !== void 0 ? _g : true; // ok
106+
var e = (_h = (i++, i++)) !== null && _h !== void 0 ? _h : true; // error
107+
var f = (_j = (maybe, i++)) !== null && _j !== void 0 ? _j : true; // error
108+
}

tests/baselines/reference/predicateSemantics.symbols

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,28 @@ function foo(this: Object | undefined) {
7979
return this ?? 0;
8080
>this : Symbol(this, Decl(predicateSemantics.ts, 40, 13))
8181
}
82+
83+
// https://github.com/microsoft/TypeScript/issues/60401
84+
{
85+
const maybe = null as true | null;
86+
>maybe : Symbol(maybe, Decl(predicateSemantics.ts, 47, 7))
87+
88+
let i = 0;
89+
>i : Symbol(i, Decl(predicateSemantics.ts, 48, 5))
90+
91+
const d = (i++, maybe) ?? true; // ok
92+
>d : Symbol(d, Decl(predicateSemantics.ts, 49, 7))
93+
>i : Symbol(i, Decl(predicateSemantics.ts, 48, 5))
94+
>maybe : Symbol(maybe, Decl(predicateSemantics.ts, 47, 7))
95+
96+
const e = (i++, i++) ?? true; // error
97+
>e : Symbol(e, Decl(predicateSemantics.ts, 50, 7))
98+
>i : Symbol(i, Decl(predicateSemantics.ts, 48, 5))
99+
>i : Symbol(i, Decl(predicateSemantics.ts, 48, 5))
100+
101+
const f = (maybe, i++) ?? true; // error
102+
>f : Symbol(f, Decl(predicateSemantics.ts, 51, 7))
103+
>maybe : Symbol(maybe, Decl(predicateSemantics.ts, 47, 7))
104+
>i : Symbol(i, Decl(predicateSemantics.ts, 48, 5))
105+
}
106+

tests/baselines/reference/predicateSemantics.types

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,77 @@ function foo(this: Object | undefined) {
234234
>0 : 0
235235
> : ^
236236
}
237+
238+
// https://github.com/microsoft/TypeScript/issues/60401
239+
{
240+
const maybe = null as true | null;
241+
>maybe : true
242+
> : ^^^^
243+
>null as true | null : true
244+
> : ^^^^
245+
>true : true
246+
> : ^^^^
247+
248+
let i = 0;
249+
>i : number
250+
> : ^^^^^^
251+
>0 : 0
252+
> : ^
253+
254+
const d = (i++, maybe) ?? true; // ok
255+
>d : true
256+
> : ^^^^
257+
>(i++, maybe) ?? true : true
258+
> : ^^^^
259+
>(i++, maybe) : true
260+
> : ^^^^
261+
>i++, maybe : true
262+
> : ^^^^
263+
>i++ : number
264+
> : ^^^^^^
265+
>i : number
266+
> : ^^^^^^
267+
>maybe : true
268+
> : ^^^^
269+
>true : true
270+
> : ^^^^
271+
272+
const e = (i++, i++) ?? true; // error
273+
>e : number | true
274+
> : ^^^^^^^^^^^^^
275+
>(i++, i++) ?? true : number | true
276+
> : ^^^^^^^^^^^^^
277+
>(i++, i++) : number
278+
> : ^^^^^^
279+
>i++, i++ : number
280+
> : ^^^^^^
281+
>i++ : number
282+
> : ^^^^^^
283+
>i : number
284+
> : ^^^^^^
285+
>i++ : number
286+
> : ^^^^^^
287+
>i : number
288+
> : ^^^^^^
289+
>true : true
290+
> : ^^^^
291+
292+
const f = (maybe, i++) ?? true; // error
293+
>f : number | true
294+
> : ^^^^^^^^^^^^^
295+
>(maybe, i++) ?? true : number | true
296+
> : ^^^^^^^^^^^^^
297+
>(maybe, i++) : number
298+
> : ^^^^^^
299+
>maybe, i++ : number
300+
> : ^^^^^^
301+
>maybe : true
302+
> : ^^^^
303+
>i++ : number
304+
> : ^^^^^^
305+
>i : number
306+
> : ^^^^^^
307+
>true : true
308+
> : ^^^^
309+
}
310+

tests/cases/compiler/predicateSemantics.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,13 @@ console.log((cond || undefined) && 1 / cond);
4141
function foo(this: Object | undefined) {
4242
// Should be OK
4343
return this ?? 0;
44-
}
44+
}
45+
46+
// https://github.com/microsoft/TypeScript/issues/60401
47+
{
48+
const maybe = null as true | null;
49+
let i = 0;
50+
const d = (i++, maybe) ?? true; // ok
51+
const e = (i++, i++) ?? true; // error
52+
const f = (maybe, i++) ?? true; // error
53+
}

0 commit comments

Comments
 (0)