From 3652682f525cd57469b3c84b5baea5270878c3c0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 30 Aug 2022 14:26:34 -0700 Subject: [PATCH 1/4] {} & null and {} & undefined should be never in non-strictNullChecks mode --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e911d7fe7d2a3..1f76cbdafd1d1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15166,7 +15166,7 @@ namespace ts { return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType; } if (!strictNullChecks && includes & TypeFlags.Nullable) { - return includes & TypeFlags.Undefined ? undefinedType : nullType; + return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType; } if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || From dd32cf8203973d4c53417800c0491b5c3ecab78b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 30 Aug 2022 14:52:31 -0700 Subject: [PATCH 2/4] Add tests --- .../reference/NonNullableInNonStrictMode.js | 21 +++++++++ .../NonNullableInNonStrictMode.symbols | 45 +++++++++++++++++++ .../NonNullableInNonStrictMode.types | 43 ++++++++++++++++++ .../compiler/NonNullableInNonStrictMode.ts | 18 ++++++++ 4 files changed, 127 insertions(+) create mode 100644 tests/baselines/reference/NonNullableInNonStrictMode.js create mode 100644 tests/baselines/reference/NonNullableInNonStrictMode.symbols create mode 100644 tests/baselines/reference/NonNullableInNonStrictMode.types create mode 100644 tests/cases/compiler/NonNullableInNonStrictMode.ts diff --git a/tests/baselines/reference/NonNullableInNonStrictMode.js b/tests/baselines/reference/NonNullableInNonStrictMode.js new file mode 100644 index 0000000000000..e5a577ed7ba88 --- /dev/null +++ b/tests/baselines/reference/NonNullableInNonStrictMode.js @@ -0,0 +1,21 @@ +//// [NonNullableInNonStrictMode.ts] +// These should all resolve to never + +type T0 = NonNullable; +type T1 = NonNullable; +type T2 = null & {}; +type T3 = undefined & {}; +type T4 = null & undefined; +type T6 = null & { a: string } & {}; + +// Repro from #50519 + +type NonNullableNew = T & {}; +type NonNullableOld = T extends null | undefined ? never : T; + +type IsNullWithoutStrictNullChecks = NonNullableNew; +type IsAlwaysNever = NonNullableOld; + + +//// [NonNullableInNonStrictMode.js] +// These should all resolve to never diff --git a/tests/baselines/reference/NonNullableInNonStrictMode.symbols b/tests/baselines/reference/NonNullableInNonStrictMode.symbols new file mode 100644 index 0000000000000..b01bdc9cfbeee --- /dev/null +++ b/tests/baselines/reference/NonNullableInNonStrictMode.symbols @@ -0,0 +1,45 @@ +=== tests/cases/compiler/NonNullableInNonStrictMode.ts === +// These should all resolve to never + +type T0 = NonNullable; +>T0 : Symbol(T0, Decl(NonNullableInNonStrictMode.ts, 0, 0)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) + +type T1 = NonNullable; +>T1 : Symbol(T1, Decl(NonNullableInNonStrictMode.ts, 2, 28)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) + +type T2 = null & {}; +>T2 : Symbol(T2, Decl(NonNullableInNonStrictMode.ts, 3, 33)) + +type T3 = undefined & {}; +>T3 : Symbol(T3, Decl(NonNullableInNonStrictMode.ts, 4, 20)) + +type T4 = null & undefined; +>T4 : Symbol(T4, Decl(NonNullableInNonStrictMode.ts, 5, 25)) + +type T6 = null & { a: string } & {}; +>T6 : Symbol(T6, Decl(NonNullableInNonStrictMode.ts, 6, 27)) +>a : Symbol(a, Decl(NonNullableInNonStrictMode.ts, 7, 18)) + +// Repro from #50519 + +type NonNullableNew = T & {}; +>NonNullableNew : Symbol(NonNullableNew, Decl(NonNullableInNonStrictMode.ts, 7, 36)) +>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 11, 20)) +>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 11, 20)) + +type NonNullableOld = T extends null | undefined ? never : T; +>NonNullableOld : Symbol(NonNullableOld, Decl(NonNullableInNonStrictMode.ts, 11, 32)) +>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20)) +>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20)) +>T : Symbol(T, Decl(NonNullableInNonStrictMode.ts, 12, 20)) + +type IsNullWithoutStrictNullChecks = NonNullableNew; +>IsNullWithoutStrictNullChecks : Symbol(IsNullWithoutStrictNullChecks, Decl(NonNullableInNonStrictMode.ts, 12, 64)) +>NonNullableNew : Symbol(NonNullableNew, Decl(NonNullableInNonStrictMode.ts, 7, 36)) + +type IsAlwaysNever = NonNullableOld; +>IsAlwaysNever : Symbol(IsAlwaysNever, Decl(NonNullableInNonStrictMode.ts, 14, 58)) +>NonNullableOld : Symbol(NonNullableOld, Decl(NonNullableInNonStrictMode.ts, 11, 32)) + diff --git a/tests/baselines/reference/NonNullableInNonStrictMode.types b/tests/baselines/reference/NonNullableInNonStrictMode.types new file mode 100644 index 0000000000000..cb2894ce0526b --- /dev/null +++ b/tests/baselines/reference/NonNullableInNonStrictMode.types @@ -0,0 +1,43 @@ +=== tests/cases/compiler/NonNullableInNonStrictMode.ts === +// These should all resolve to never + +type T0 = NonNullable; +>T0 : never +>null : null + +type T1 = NonNullable; +>T1 : never + +type T2 = null & {}; +>T2 : never +>null : null + +type T3 = undefined & {}; +>T3 : never + +type T4 = null & undefined; +>T4 : never +>null : null + +type T6 = null & { a: string } & {}; +>T6 : never +>null : null +>a : string + +// Repro from #50519 + +type NonNullableNew = T & {}; +>NonNullableNew : NonNullableNew + +type NonNullableOld = T extends null | undefined ? never : T; +>NonNullableOld : NonNullableOld +>null : null + +type IsNullWithoutStrictNullChecks = NonNullableNew; +>IsNullWithoutStrictNullChecks : never +>null : null + +type IsAlwaysNever = NonNullableOld; +>IsAlwaysNever : never +>null : null + diff --git a/tests/cases/compiler/NonNullableInNonStrictMode.ts b/tests/cases/compiler/NonNullableInNonStrictMode.ts new file mode 100644 index 0000000000000..73ee96c39ee79 --- /dev/null +++ b/tests/cases/compiler/NonNullableInNonStrictMode.ts @@ -0,0 +1,18 @@ +// @strict: false + +// These should all resolve to never + +type T0 = NonNullable; +type T1 = NonNullable; +type T2 = null & {}; +type T3 = undefined & {}; +type T4 = null & undefined; +type T6 = null & { a: string } & {}; + +// Repro from #50519 + +type NonNullableNew = T & {}; +type NonNullableOld = T extends null | undefined ? never : T; + +type IsNullWithoutStrictNullChecks = NonNullableNew; +type IsAlwaysNever = NonNullableOld; From 03cb73ffe1941ea4e915ac00e99bdeb9f063161d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 1 Sep 2022 07:52:15 -0700 Subject: [PATCH 3/4] Address code review feedback --- ...onStrictMode.ts => nonNullableAndObjectIntersections.ts} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/cases/compiler/{NonNullableInNonStrictMode.ts => nonNullableAndObjectIntersections.ts} (70%) diff --git a/tests/cases/compiler/NonNullableInNonStrictMode.ts b/tests/cases/compiler/nonNullableAndObjectIntersections.ts similarity index 70% rename from tests/cases/compiler/NonNullableInNonStrictMode.ts rename to tests/cases/compiler/nonNullableAndObjectIntersections.ts index 73ee96c39ee79..a9e8319aef266 100644 --- a/tests/cases/compiler/NonNullableInNonStrictMode.ts +++ b/tests/cases/compiler/nonNullableAndObjectIntersections.ts @@ -1,4 +1,4 @@ -// @strict: false +// @strict: true, false // These should all resolve to never @@ -14,5 +14,5 @@ type T6 = null & { a: string } & {}; type NonNullableNew = T & {}; type NonNullableOld = T extends null | undefined ? never : T; -type IsNullWithoutStrictNullChecks = NonNullableNew; -type IsAlwaysNever = NonNullableOld; +type TestNew = NonNullableNew; +type TestOld = NonNullableOld; From 45025535ced1aaff1a4eb1a956f4469ce27c1ae6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 1 Sep 2022 07:52:37 -0700 Subject: [PATCH 4/4] Accept new baselines --- ...bleAndObjectIntersections(strict=false).js | 21 +++++++++ ...dObjectIntersections(strict=false).symbols | 45 +++++++++++++++++++ ...AndObjectIntersections(strict=false).types | 43 ++++++++++++++++++ ...ableAndObjectIntersections(strict=true).js | 22 +++++++++ ...ndObjectIntersections(strict=true).symbols | 45 +++++++++++++++++++ ...eAndObjectIntersections(strict=true).types | 43 ++++++++++++++++++ 6 files changed, 219 insertions(+) create mode 100644 tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).js create mode 100644 tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).symbols create mode 100644 tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).types create mode 100644 tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).js create mode 100644 tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).symbols create mode 100644 tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).types diff --git a/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).js b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).js new file mode 100644 index 0000000000000..1ac2c23d4a83a --- /dev/null +++ b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).js @@ -0,0 +1,21 @@ +//// [nonNullableAndObjectIntersections.ts] +// These should all resolve to never + +type T0 = NonNullable; +type T1 = NonNullable; +type T2 = null & {}; +type T3 = undefined & {}; +type T4 = null & undefined; +type T6 = null & { a: string } & {}; + +// Repro from #50519 + +type NonNullableNew = T & {}; +type NonNullableOld = T extends null | undefined ? never : T; + +type TestNew = NonNullableNew; +type TestOld = NonNullableOld; + + +//// [nonNullableAndObjectIntersections.js] +// These should all resolve to never diff --git a/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).symbols b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).symbols new file mode 100644 index 0000000000000..1d4558399dbbf --- /dev/null +++ b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).symbols @@ -0,0 +1,45 @@ +=== tests/cases/compiler/nonNullableAndObjectIntersections.ts === +// These should all resolve to never + +type T0 = NonNullable; +>T0 : Symbol(T0, Decl(nonNullableAndObjectIntersections.ts, 0, 0)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) + +type T1 = NonNullable; +>T1 : Symbol(T1, Decl(nonNullableAndObjectIntersections.ts, 2, 28)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) + +type T2 = null & {}; +>T2 : Symbol(T2, Decl(nonNullableAndObjectIntersections.ts, 3, 33)) + +type T3 = undefined & {}; +>T3 : Symbol(T3, Decl(nonNullableAndObjectIntersections.ts, 4, 20)) + +type T4 = null & undefined; +>T4 : Symbol(T4, Decl(nonNullableAndObjectIntersections.ts, 5, 25)) + +type T6 = null & { a: string } & {}; +>T6 : Symbol(T6, Decl(nonNullableAndObjectIntersections.ts, 6, 27)) +>a : Symbol(a, Decl(nonNullableAndObjectIntersections.ts, 7, 18)) + +// Repro from #50519 + +type NonNullableNew = T & {}; +>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20)) + +type NonNullableOld = T extends null | undefined ? never : T; +>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20)) + +type TestNew = NonNullableNew; +>TestNew : Symbol(TestNew, Decl(nonNullableAndObjectIntersections.ts, 12, 64)) +>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36)) + +type TestOld = NonNullableOld; +>TestOld : Symbol(TestOld, Decl(nonNullableAndObjectIntersections.ts, 14, 36)) +>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32)) + diff --git a/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).types b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).types new file mode 100644 index 0000000000000..19b4e9c5f06e7 --- /dev/null +++ b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=false).types @@ -0,0 +1,43 @@ +=== tests/cases/compiler/nonNullableAndObjectIntersections.ts === +// These should all resolve to never + +type T0 = NonNullable; +>T0 : never +>null : null + +type T1 = NonNullable; +>T1 : never + +type T2 = null & {}; +>T2 : never +>null : null + +type T3 = undefined & {}; +>T3 : never + +type T4 = null & undefined; +>T4 : never +>null : null + +type T6 = null & { a: string } & {}; +>T6 : never +>null : null +>a : string + +// Repro from #50519 + +type NonNullableNew = T & {}; +>NonNullableNew : NonNullableNew + +type NonNullableOld = T extends null | undefined ? never : T; +>NonNullableOld : NonNullableOld +>null : null + +type TestNew = NonNullableNew; +>TestNew : never +>null : null + +type TestOld = NonNullableOld; +>TestOld : never +>null : null + diff --git a/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).js b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).js new file mode 100644 index 0000000000000..51b88571c735e --- /dev/null +++ b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).js @@ -0,0 +1,22 @@ +//// [nonNullableAndObjectIntersections.ts] +// These should all resolve to never + +type T0 = NonNullable; +type T1 = NonNullable; +type T2 = null & {}; +type T3 = undefined & {}; +type T4 = null & undefined; +type T6 = null & { a: string } & {}; + +// Repro from #50519 + +type NonNullableNew = T & {}; +type NonNullableOld = T extends null | undefined ? never : T; + +type TestNew = NonNullableNew; +type TestOld = NonNullableOld; + + +//// [nonNullableAndObjectIntersections.js] +"use strict"; +// These should all resolve to never diff --git a/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).symbols b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).symbols new file mode 100644 index 0000000000000..1d4558399dbbf --- /dev/null +++ b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).symbols @@ -0,0 +1,45 @@ +=== tests/cases/compiler/nonNullableAndObjectIntersections.ts === +// These should all resolve to never + +type T0 = NonNullable; +>T0 : Symbol(T0, Decl(nonNullableAndObjectIntersections.ts, 0, 0)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) + +type T1 = NonNullable; +>T1 : Symbol(T1, Decl(nonNullableAndObjectIntersections.ts, 2, 28)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) + +type T2 = null & {}; +>T2 : Symbol(T2, Decl(nonNullableAndObjectIntersections.ts, 3, 33)) + +type T3 = undefined & {}; +>T3 : Symbol(T3, Decl(nonNullableAndObjectIntersections.ts, 4, 20)) + +type T4 = null & undefined; +>T4 : Symbol(T4, Decl(nonNullableAndObjectIntersections.ts, 5, 25)) + +type T6 = null & { a: string } & {}; +>T6 : Symbol(T6, Decl(nonNullableAndObjectIntersections.ts, 6, 27)) +>a : Symbol(a, Decl(nonNullableAndObjectIntersections.ts, 7, 18)) + +// Repro from #50519 + +type NonNullableNew = T & {}; +>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 11, 20)) + +type NonNullableOld = T extends null | undefined ? never : T; +>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20)) +>T : Symbol(T, Decl(nonNullableAndObjectIntersections.ts, 12, 20)) + +type TestNew = NonNullableNew; +>TestNew : Symbol(TestNew, Decl(nonNullableAndObjectIntersections.ts, 12, 64)) +>NonNullableNew : Symbol(NonNullableNew, Decl(nonNullableAndObjectIntersections.ts, 7, 36)) + +type TestOld = NonNullableOld; +>TestOld : Symbol(TestOld, Decl(nonNullableAndObjectIntersections.ts, 14, 36)) +>NonNullableOld : Symbol(NonNullableOld, Decl(nonNullableAndObjectIntersections.ts, 11, 32)) + diff --git a/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).types b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).types new file mode 100644 index 0000000000000..19b4e9c5f06e7 --- /dev/null +++ b/tests/baselines/reference/nonNullableAndObjectIntersections(strict=true).types @@ -0,0 +1,43 @@ +=== tests/cases/compiler/nonNullableAndObjectIntersections.ts === +// These should all resolve to never + +type T0 = NonNullable; +>T0 : never +>null : null + +type T1 = NonNullable; +>T1 : never + +type T2 = null & {}; +>T2 : never +>null : null + +type T3 = undefined & {}; +>T3 : never + +type T4 = null & undefined; +>T4 : never +>null : null + +type T6 = null & { a: string } & {}; +>T6 : never +>null : null +>a : string + +// Repro from #50519 + +type NonNullableNew = T & {}; +>NonNullableNew : NonNullableNew + +type NonNullableOld = T extends null | undefined ? never : T; +>NonNullableOld : NonNullableOld +>null : null + +type TestNew = NonNullableNew; +>TestNew : never +>null : null + +type TestOld = NonNullableOld; +>TestOld : never +>null : null +