Skip to content

Commit 3ee0907

Browse files
committed
Fix CFA for with generic T (#62133)
1 parent be86783 commit 3ee0907

7 files changed

Lines changed: 2361 additions & 190 deletions

File tree

package-lock.json

Lines changed: 2190 additions & 190 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,8 @@
115115
"volta": {
116116
"node": "20.1.0",
117117
"npm": "8.19.4"
118+
},
119+
"dependencies": {
120+
"gulp": "^5.0.1"
118121
}
119122
}

src/compiler/checker.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25677,6 +25677,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2567725677
}
2567825678

2567925679
function getDefinitelyFalsyPartOfType(type: Type): Type {
25680+
if (type.flags & TypeFlags.TypeParameter) {
25681+
const constraint = getBaseConstraintOfType(type);
25682+
if (!constraint || constraint === type) {
25683+
return neverType;
25684+
}
25685+
return getDefinitelyFalsyPartOfType(constraint);
25686+
}
25687+
2568025688
return type.flags & TypeFlags.String ? emptyStringType :
2568125689
type.flags & TypeFlags.Number ? zeroType :
2568225690
type.flags & TypeFlags.BigInt ? zeroBigIntType :
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [tests/cases/compiler/andAndGeneric.ts] ////
2+
3+
//// [andAndGeneric.ts]
4+
declare function id<T>(x: T): T;
5+
6+
function f<T>(x: T) {
7+
return id(x && x); // should NOT be narrowed to NonNullable<T>
8+
}
9+
10+
// ---- expected types ----
11+
const t1 = f(null); // null (currently incorrectly NonNullable<null> -> never)
12+
const t2 = f(0); // 0
13+
const t3 = f(1); // 1
14+
const t4 = f<"a" | null>("a"); // "a"
15+
const t5 = f<"a" | null>(null); // null
16+
17+
18+
//// [andAndGeneric.js]
19+
"use strict";
20+
function f(x) {
21+
return id(x && x); // should NOT be narrowed to NonNullable<T>
22+
}
23+
// ---- expected types ----
24+
var t1 = f(null); // null (currently incorrectly NonNullable<null> -> never)
25+
var t2 = f(0); // 0
26+
var t3 = f(1); // 1
27+
var t4 = f("a"); // "a"
28+
var t5 = f(null); // null
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//// [tests/cases/compiler/andAndGeneric.ts] ////
2+
3+
=== andAndGeneric.ts ===
4+
declare function id<T>(x: T): T;
5+
>id : Symbol(id, Decl(andAndGeneric.ts, 0, 0))
6+
>T : Symbol(T, Decl(andAndGeneric.ts, 0, 20))
7+
>x : Symbol(x, Decl(andAndGeneric.ts, 0, 23))
8+
>T : Symbol(T, Decl(andAndGeneric.ts, 0, 20))
9+
>T : Symbol(T, Decl(andAndGeneric.ts, 0, 20))
10+
11+
function f<T>(x: T) {
12+
>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32))
13+
>T : Symbol(T, Decl(andAndGeneric.ts, 2, 11))
14+
>x : Symbol(x, Decl(andAndGeneric.ts, 2, 14))
15+
>T : Symbol(T, Decl(andAndGeneric.ts, 2, 11))
16+
17+
return id(x && x); // should NOT be narrowed to NonNullable<T>
18+
>id : Symbol(id, Decl(andAndGeneric.ts, 0, 0))
19+
>x : Symbol(x, Decl(andAndGeneric.ts, 2, 14))
20+
>x : Symbol(x, Decl(andAndGeneric.ts, 2, 14))
21+
}
22+
23+
// ---- expected types ----
24+
const t1 = f(null); // null (currently incorrectly NonNullable<null> -> never)
25+
>t1 : Symbol(t1, Decl(andAndGeneric.ts, 7, 5))
26+
>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32))
27+
28+
const t2 = f(0); // 0
29+
>t2 : Symbol(t2, Decl(andAndGeneric.ts, 8, 5))
30+
>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32))
31+
32+
const t3 = f(1); // 1
33+
>t3 : Symbol(t3, Decl(andAndGeneric.ts, 9, 5))
34+
>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32))
35+
36+
const t4 = f<"a" | null>("a"); // "a"
37+
>t4 : Symbol(t4, Decl(andAndGeneric.ts, 10, 5))
38+
>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32))
39+
40+
const t5 = f<"a" | null>(null); // null
41+
>t5 : Symbol(t5, Decl(andAndGeneric.ts, 11, 5))
42+
>f : Symbol(f, Decl(andAndGeneric.ts, 0, 32))
43+
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//// [tests/cases/compiler/andAndGeneric.ts] ////
2+
3+
=== andAndGeneric.ts ===
4+
declare function id<T>(x: T): T;
5+
>id : <T>(x: T) => T
6+
> : ^ ^^ ^^ ^^^^^
7+
>x : T
8+
> : ^
9+
10+
function f<T>(x: T) {
11+
>f : <T>(x: T) => NonNullable<T>
12+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
13+
>x : T
14+
> : ^
15+
16+
return id(x && x); // should NOT be narrowed to NonNullable<T>
17+
>id(x && x) : NonNullable<T>
18+
> : ^^^^^^^^^^^^^^
19+
>id : <T_1>(x: T_1) => T_1
20+
> : ^^^^^^ ^^ ^^^^^
21+
>x && x : NonNullable<T>
22+
> : ^^^^^^^^^^^^^^
23+
>x : T
24+
> : ^
25+
>x : NonNullable<T>
26+
> : ^^^^^^^^^^^^^^
27+
}
28+
29+
// ---- expected types ----
30+
const t1 = f(null); // null (currently incorrectly NonNullable<null> -> never)
31+
>t1 : never
32+
> : ^^^^^
33+
>f(null) : never
34+
> : ^^^^^
35+
>f : <T>(x: T) => NonNullable<T>
36+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
37+
38+
const t2 = f(0); // 0
39+
>t2 : 0
40+
> : ^
41+
>f(0) : 0
42+
> : ^
43+
>f : <T>(x: T) => NonNullable<T>
44+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
45+
>0 : 0
46+
> : ^
47+
48+
const t3 = f(1); // 1
49+
>t3 : 1
50+
> : ^
51+
>f(1) : 1
52+
> : ^
53+
>f : <T>(x: T) => NonNullable<T>
54+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
55+
>1 : 1
56+
> : ^
57+
58+
const t4 = f<"a" | null>("a"); // "a"
59+
>t4 : "a"
60+
> : ^^^
61+
>f<"a" | null>("a") : "a"
62+
> : ^^^
63+
>f : <T>(x: T) => NonNullable<T>
64+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
65+
>"a" : "a"
66+
> : ^^^
67+
68+
const t5 = f<"a" | null>(null); // null
69+
>t5 : "a"
70+
> : ^^^
71+
>f<"a" | null>(null) : "a"
72+
> : ^^^
73+
>f : <T>(x: T) => NonNullable<T>
74+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
75+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @strict: true
2+
3+
declare function id<T>(x: T): T;
4+
5+
function f<T>(x: T) {
6+
return id(x && x); // should NOT be narrowed to NonNullable<T>
7+
}
8+
9+
// ---- expected types ----
10+
const t1 = f(null); // null (currently incorrectly NonNullable<null> -> never)
11+
const t2 = f(0); // 0
12+
const t3 = f(1); // 1
13+
const t4 = f<"a" | null>("a"); // "a"
14+
const t5 = f<"a" | null>(null); // null

0 commit comments

Comments
 (0)