From 5a567ad56dac117340a77616504bb666adf3f5e0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 27 Apr 2019 09:56:01 -0700 Subject: [PATCH 1/4] Properly instantiate true type when extends type is any or unknown --- 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 8ee0a4c051996..1431f877d8e32 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10383,7 +10383,7 @@ namespace ts { // We attempt to resolve the conditional type only when the check and extends types are non-generic if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable | TypeFlags.GenericMappedType)) { if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) { - return trueType; + return instantiateType(root.trueType, combinedMapper || mapper); } // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any) { From 078375765be69838f06eb22386820d19e75ee065 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 27 Apr 2019 09:56:11 -0700 Subject: [PATCH 2/4] Add regression test --- tests/cases/conformance/types/conditional/inferTypes2.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/cases/conformance/types/conditional/inferTypes2.ts b/tests/cases/conformance/types/conditional/inferTypes2.ts index fbf4ca808336e..77b910c511385 100644 --- a/tests/cases/conformance/types/conditional/inferTypes2.ts +++ b/tests/cases/conformance/types/conditional/inferTypes2.ts @@ -14,3 +14,11 @@ export declare function foo2(obj: T): T extends { [K in keyof BadNested(obj: T) { return foo2(obj); } + +// Repros from #31099 + +type Weird = any extends infer U ? U : never; +type AlsoWeird = unknown extends infer U ? U : never; + +const a: Weird = null; +const b: string = a; From 19bdaf8644c15b7db7567fb0204cfb971d7dd2b4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 27 Apr 2019 09:56:17 -0700 Subject: [PATCH 3/4] Accept new baselines --- tests/baselines/reference/inferTypes2.js | 10 ++++++++++ tests/baselines/reference/inferTypes2.symbols | 20 +++++++++++++++++++ tests/baselines/reference/inferTypes2.types | 16 +++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/tests/baselines/reference/inferTypes2.js b/tests/baselines/reference/inferTypes2.js index 2b2c318716aa9..b71a339f3e079 100644 --- a/tests/baselines/reference/inferTypes2.js +++ b/tests/baselines/reference/inferTypes2.js @@ -12,6 +12,14 @@ export declare function foo2(obj: T): T extends { [K in keyof BadNested(obj: T) { return foo2(obj); } + +// Repros from #31099 + +type Weird = any extends infer U ? U : never; +type AlsoWeird = unknown extends infer U ? U : never; + +const a: Weird = null; +const b: string = a; //// [inferTypes2.js] @@ -26,6 +34,8 @@ function bar2(obj) { return foo2(obj); } exports.bar2 = bar2; +var a = null; +var b = a; //// [inferTypes2.d.ts] diff --git a/tests/baselines/reference/inferTypes2.symbols b/tests/baselines/reference/inferTypes2.symbols index d32d9a7012bee..8d792ea79c225 100644 --- a/tests/baselines/reference/inferTypes2.symbols +++ b/tests/baselines/reference/inferTypes2.symbols @@ -53,3 +53,23 @@ export function bar2(obj: T) { >obj : Symbol(obj, Decl(inferTypes2.ts, 10, 24)) } +// Repros from #31099 + +type Weird = any extends infer U ? U : never; +>Weird : Symbol(Weird, Decl(inferTypes2.ts, 12, 1)) +>U : Symbol(U, Decl(inferTypes2.ts, 16, 30)) +>U : Symbol(U, Decl(inferTypes2.ts, 16, 30)) + +type AlsoWeird = unknown extends infer U ? U : never; +>AlsoWeird : Symbol(AlsoWeird, Decl(inferTypes2.ts, 16, 45)) +>U : Symbol(U, Decl(inferTypes2.ts, 17, 38)) +>U : Symbol(U, Decl(inferTypes2.ts, 17, 38)) + +const a: Weird = null; +>a : Symbol(a, Decl(inferTypes2.ts, 19, 5)) +>Weird : Symbol(Weird, Decl(inferTypes2.ts, 12, 1)) + +const b: string = a; +>b : Symbol(b, Decl(inferTypes2.ts, 20, 5)) +>a : Symbol(a, Decl(inferTypes2.ts, 19, 5)) + diff --git a/tests/baselines/reference/inferTypes2.types b/tests/baselines/reference/inferTypes2.types index 95fec4307569e..04ca9ea6d0553 100644 --- a/tests/baselines/reference/inferTypes2.types +++ b/tests/baselines/reference/inferTypes2.types @@ -33,3 +33,19 @@ export function bar2(obj: T) { >obj : T } +// Repros from #31099 + +type Weird = any extends infer U ? U : never; +>Weird : any + +type AlsoWeird = unknown extends infer U ? U : never; +>AlsoWeird : unknown + +const a: Weird = null; +>a : any +>null : null + +const b: string = a; +>b : string +>a : any + From 31551fd0aecd8ed63f0f53b3d02d50b3968ed9ac Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 29 Apr 2019 17:17:16 -0700 Subject: [PATCH 4/4] Only instantiate types if we need to --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1431f877d8e32..0ac9a996157e6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10383,11 +10383,11 @@ namespace ts { // We attempt to resolve the conditional type only when the check and extends types are non-generic if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable | TypeFlags.GenericMappedType)) { if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) { - return instantiateType(root.trueType, combinedMapper || mapper); + return combinedMapper ? instantiateType(root.trueType, combinedMapper) : trueType; } // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any) { - return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), falseType]); + return getUnionType([combinedMapper ? instantiateType(root.trueType, combinedMapper) : trueType, falseType]); } // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations @@ -10402,7 +10402,7 @@ namespace ts { // type Foo = T extends { x: string } ? string : number // doesn't immediately resolve to 'string' instead of being deferred. if (isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) { - return instantiateType(root.trueType, combinedMapper || mapper); + return combinedMapper ? instantiateType(root.trueType, combinedMapper) : trueType; } } // Return a deferred type for a check that is neither definitely true nor definitely false