Skip to content

Commit e844dc3

Browse files
jakebaileyAndaristRyanCavanaugh
authored
Cherry-pick #60402, #60440, #60616 into release-5.7 (#60777)
Co-authored-by: Mateusz Burzyński <[email protected]> Co-authored-by: Ryan Cavanaugh <[email protected]>
1 parent 21b02a1 commit e844dc3

File tree

6 files changed

+330
-5
lines changed

6 files changed

+330
-5
lines changed

Diff for: src/compiler/checker.ts

+4
Original file line numberDiff line numberDiff line change
@@ -39783,7 +39783,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3978339783
switch (node.kind) {
3978439784
case SyntaxKind.AwaitExpression:
3978539785
case SyntaxKind.CallExpression:
39786+
case SyntaxKind.TaggedTemplateExpression:
3978639787
case SyntaxKind.ElementAccessExpression:
39788+
case SyntaxKind.MetaProperty:
3978739789
case SyntaxKind.NewExpression:
3978839790
case SyntaxKind.PropertyAccessExpression:
3978939791
case SyntaxKind.YieldExpression:
@@ -39801,6 +39803,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3980139803
case SyntaxKind.AmpersandAmpersandToken:
3980239804
case SyntaxKind.AmpersandAmpersandEqualsToken:
3980339805
return PredicateSemantics.Sometimes;
39806+
case SyntaxKind.CommaToken:
39807+
return getSyntacticNullishnessSemantics((node as BinaryExpression).right);
3980439808
}
3980539809
return PredicateSemantics.Never;
3980639810
case SyntaxKind.ConditionalExpression:

Diff for: tests/baselines/reference/predicateSemantics.errors.txt

+45-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ 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.
15+
predicateSemantics.ts(70,1): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
16+
predicateSemantics.ts(71,1): error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
1217

1318

14-
==== predicateSemantics.ts (11 errors) ====
19+
==== predicateSemantics.ts (16 errors) ====
1520
declare let cond: any;
1621

1722
// OK: One or other operand is possibly nullish
@@ -77,4 +82,42 @@ predicateSemantics.ts(36,8): error TS2872: This kind of expression is always tru
7782
function foo(this: Object | undefined) {
7883
// Should be OK
7984
return this ?? 0;
80-
}
85+
}
86+
87+
// https://github.com/microsoft/TypeScript/issues/60401
88+
{
89+
const maybe = null as true | null;
90+
let i = 0;
91+
const d = (i++, maybe) ?? true; // ok
92+
const e = (i++, i++) ?? true; // error
93+
~~~~~~~~
94+
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
95+
const f = (maybe, i++) ?? true; // error
96+
~~~~~
97+
!!! error TS2695: Left side of comma operator is unused and has no side effects.
98+
~~~~~~~~~~
99+
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
100+
}
101+
102+
// https://github.com/microsoft/TypeScript/issues/60439
103+
class X {
104+
constructor() {
105+
const p = new.target ?? 32;
106+
}
107+
}
108+
109+
// https://github.com/microsoft/TypeScript/issues/60614
110+
declare function tag<T>(
111+
strings: TemplateStringsArray,
112+
...values: number[]
113+
): T | null;
114+
115+
tag`foo${1}` ?? 32; // ok
116+
117+
`foo${1}` ?? 32; // error
118+
~~~~~~~~~
119+
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
120+
`foo` ?? 32; // error
121+
~~~~~
122+
!!! error TS2869: Right operand of ?? is unreachable because the left operand is never nullish.
123+

Diff for: tests/baselines/reference/predicateSemantics.js

+54-2
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,42 @@ 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+
58+
// https://github.com/microsoft/TypeScript/issues/60439
59+
class X {
60+
constructor() {
61+
const p = new.target ?? 32;
62+
}
63+
}
64+
65+
// https://github.com/microsoft/TypeScript/issues/60614
66+
declare function tag<T>(
67+
strings: TemplateStringsArray,
68+
...values: number[]
69+
): T | null;
70+
71+
tag`foo${1}` ?? 32; // ok
72+
73+
`foo${1}` ?? 32; // error
74+
`foo` ?? 32; // error
75+
4876

4977
//// [predicateSemantics.js]
50-
var _a, _b, _c, _d, _e, _f;
78+
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
79+
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
80+
return cooked;
81+
};
82+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
5183
// OK: One or other operand is possibly nullish
5284
var test1 = (_a = (cond ? undefined : 32)) !== null && _a !== void 0 ? _a : "possibly reached";
5385
// Not OK: Both operands nullish
@@ -88,3 +120,23 @@ function foo() {
88120
// Should be OK
89121
return this !== null && this !== void 0 ? this : 0;
90122
}
123+
// https://github.com/microsoft/TypeScript/issues/60401
124+
{
125+
var maybe = null;
126+
var i = 0;
127+
var d = (_g = (i++, maybe)) !== null && _g !== void 0 ? _g : true; // ok
128+
var e = (_h = (i++, i++)) !== null && _h !== void 0 ? _h : true; // error
129+
var f = (_j = (maybe, i++)) !== null && _j !== void 0 ? _j : true; // error
130+
}
131+
// https://github.com/microsoft/TypeScript/issues/60439
132+
var X = /** @class */ (function () {
133+
function X() {
134+
var _newTarget = this.constructor;
135+
var _a;
136+
var p = (_a = _newTarget) !== null && _a !== void 0 ? _a : 32;
137+
}
138+
return X;
139+
}());
140+
(_k = tag(__makeTemplateObject(["foo", ""], ["foo", ""]), 1)) !== null && _k !== void 0 ? _k : 32; // ok
141+
(_l = "foo".concat(1)) !== null && _l !== void 0 ? _l : 32; // error
142+
"foo" !== null && "foo" !== void 0 ? "foo" : 32; // error

Diff for: tests/baselines/reference/predicateSemantics.symbols

+58
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,61 @@ 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+
107+
// https://github.com/microsoft/TypeScript/issues/60439
108+
class X {
109+
>X : Symbol(X, Decl(predicateSemantics.ts, 52, 1))
110+
111+
constructor() {
112+
const p = new.target ?? 32;
113+
>p : Symbol(p, Decl(predicateSemantics.ts, 57, 9))
114+
>new.target : Symbol(X, Decl(predicateSemantics.ts, 52, 1))
115+
>target : Symbol(X, Decl(predicateSemantics.ts, 52, 1))
116+
}
117+
}
118+
119+
// https://github.com/microsoft/TypeScript/issues/60614
120+
declare function tag<T>(
121+
>tag : Symbol(tag, Decl(predicateSemantics.ts, 59, 1))
122+
>T : Symbol(T, Decl(predicateSemantics.ts, 62, 21))
123+
124+
strings: TemplateStringsArray,
125+
>strings : Symbol(strings, Decl(predicateSemantics.ts, 62, 24))
126+
>TemplateStringsArray : Symbol(TemplateStringsArray, Decl(lib.es5.d.ts, --, --))
127+
128+
...values: number[]
129+
>values : Symbol(values, Decl(predicateSemantics.ts, 63, 32))
130+
131+
): T | null;
132+
>T : Symbol(T, Decl(predicateSemantics.ts, 62, 21))
133+
134+
tag`foo${1}` ?? 32; // ok
135+
>tag : Symbol(tag, Decl(predicateSemantics.ts, 59, 1))
136+
137+
`foo${1}` ?? 32; // error
138+
`foo` ?? 32; // error
139+

Diff for: tests/baselines/reference/predicateSemantics.types

+141
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,144 @@ 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+
311+
// https://github.com/microsoft/TypeScript/issues/60439
312+
class X {
313+
>X : X
314+
> : ^
315+
316+
constructor() {
317+
const p = new.target ?? 32;
318+
>p : 32 | typeof X
319+
> : ^^^^^^^^^^^^^
320+
>new.target ?? 32 : 32 | typeof X
321+
> : ^^^^^^^^^^^^^
322+
>new.target : typeof X
323+
> : ^^^^^^^^
324+
>target : typeof X
325+
> : ^^^^^^^^
326+
>32 : 32
327+
> : ^^
328+
}
329+
}
330+
331+
// https://github.com/microsoft/TypeScript/issues/60614
332+
declare function tag<T>(
333+
>tag : <T>(strings: TemplateStringsArray, ...values: number[]) => T | null
334+
> : ^ ^^ ^^ ^^^^^ ^^ ^^^^^
335+
336+
strings: TemplateStringsArray,
337+
>strings : TemplateStringsArray
338+
> : ^^^^^^^^^^^^^^^^^^^^
339+
340+
...values: number[]
341+
>values : number[]
342+
> : ^^^^^^^^
343+
344+
): T | null;
345+
346+
tag`foo${1}` ?? 32; // ok
347+
>tag`foo${1}` ?? 32 : unknown
348+
> : ^^^^^^^
349+
>tag`foo${1}` : unknown
350+
> : ^^^^^^^
351+
>tag : <T>(strings: TemplateStringsArray, ...values: number[]) => T | null
352+
> : ^ ^^ ^^ ^^^^^ ^^ ^^^^^
353+
>`foo${1}` : string
354+
> : ^^^^^^
355+
>1 : 1
356+
> : ^
357+
>32 : 32
358+
> : ^^
359+
360+
`foo${1}` ?? 32; // error
361+
>`foo${1}` ?? 32 : 32 | "foo1"
362+
> : ^^^^^^^^^^^
363+
>`foo${1}` : "foo1"
364+
> : ^^^^^^
365+
>1 : 1
366+
> : ^
367+
>32 : 32
368+
> : ^^
369+
370+
`foo` ?? 32; // error
371+
>`foo` ?? 32 : 32 | "foo"
372+
> : ^^^^^^^^^^
373+
>`foo` : "foo"
374+
> : ^^^^^
375+
>32 : 32
376+
> : ^^
377+

Diff for: tests/cases/compiler/predicateSemantics.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,31 @@ 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+
}
54+
55+
// https://github.com/microsoft/TypeScript/issues/60439
56+
class X {
57+
constructor() {
58+
const p = new.target ?? 32;
59+
}
60+
}
61+
62+
// https://github.com/microsoft/TypeScript/issues/60614
63+
declare function tag<T>(
64+
strings: TemplateStringsArray,
65+
...values: number[]
66+
): T | null;
67+
68+
tag`foo${1}` ?? 32; // ok
69+
70+
`foo${1}` ?? 32; // error
71+
`foo` ?? 32; // error

0 commit comments

Comments
 (0)