From b8f3c6169bd23c338bb098da18dc55c50618152a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 06:48:29 -0800 Subject: [PATCH 1/3] Use more permissive wildcard type in definitely false check --- src/compiler/checker.ts | 18 ++++++++++-------- src/compiler/types.ts | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 05da314a8161c..7f75f234e52b2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -315,6 +315,7 @@ namespace ts { const anyType = createIntrinsicType(TypeFlags.Any, "any"); const autoType = createIntrinsicType(TypeFlags.Any, "any"); + const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); const unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined"); @@ -8150,9 +8151,10 @@ namespace ts { // Instantiate extends type without instantiating any 'infer T' type parameters const extendsType = instantiateType(baseExtendsType, mapper); // Return falseType for a definitely false extends check. We check an instantations of the two - // types with type parameters mapped to any, the most permissive instantiations possible. If those - // are not related, then no instatiations will be and we can just return the false branch type. - if (!isTypeAssignableTo(getAnyInstantiation(checkType), getAnyInstantiation(extendsType))) { + // types with type parameters mapped to the wildcard type, the most permissive instantiations + // possible (the wildcard type is assignable to and from all types). If those are not related, + // then no instatiations will be and we can just return the false branch type. + if (!isTypeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) { return instantiateType(baseFalseType, mapper); } // The check could be true for some instantiation @@ -8615,8 +8617,8 @@ namespace ts { return t => t === source ? target : baseMapper(t); } - function anyMapper(type: Type) { - return type.flags & TypeFlags.TypeParameter ? anyType : type; + function wildcardMapper(type: Type) { + return type.flags & TypeFlags.TypeParameter ? wildcardType : type; } function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { @@ -8873,9 +8875,9 @@ namespace ts { return type; } - function getAnyInstantiation(type: Type) { + function getWildcardInstantiation(type: Type) { return type.flags & (TypeFlags.Primitive | TypeFlags.Any | TypeFlags.Never) ? type : - type.resolvedAnyInstantiation || (type.resolvedAnyInstantiation = instantiateType(type, anyMapper)); + type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper)); } function instantiateIndexInfo(info: IndexInfo, mapper: TypeMapper): IndexInfo { @@ -9282,7 +9284,7 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Any || s & TypeFlags.Never) return true; + if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a1c49a93c303..4bf7148278c58 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3564,7 +3564,7 @@ namespace ts { aliasSymbol?: Symbol; // Alias associated with type aliasTypeArguments?: Type[]; // Alias type arguments (if any) /* @internal */ - resolvedAnyInstantiation?: Type; // Instantiation with type parameters mapped to any + wildcardInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type } /* @internal */ From 4c9e6499d5f8136c576af956d36e836c26b9227f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 06:48:38 -0800 Subject: [PATCH 2/3] Add tests --- .../types/conditional/conditionalTypes1.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/cases/conformance/types/conditional/conditionalTypes1.ts b/tests/cases/conformance/types/conditional/conditionalTypes1.ts index 6f4e7dc4188d0..a6169d428ff25 100644 --- a/tests/cases/conformance/types/conditional/conditionalTypes1.ts +++ b/tests/cases/conformance/types/conditional/conditionalTypes1.ts @@ -166,12 +166,12 @@ type Not = If; type And = If; type Or = If; -type isString = Extends; +type IsString = Extends; -type Q1 = isString; // false -type Q2 = isString<"abc">; // true -type Q3 = isString; // boolean -type Q4 = isString; // boolean +type Q1 = IsString; // false +type Q2 = IsString<"abc">; // true +type Q3 = IsString; // boolean +type Q4 = IsString; // boolean type N1 = Not; // true type N2 = Not; // false @@ -200,3 +200,9 @@ type O9 = Or; // boolean type T40 = never extends never ? true : false; // true type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean + +type IsNever = T extends never ? true : false; + +type T50 = IsNever; // true +type T51 = IsNever; // false +type T52 = IsNever; // false From d5e2f49eeefd889f1a2911ab668d2a631b17b972 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 5 Feb 2018 06:48:45 -0800 Subject: [PATCH 3/3] Accept new baselines --- .../reference/conditionalTypes1.errors.txt | 16 +++++--- .../baselines/reference/conditionalTypes1.js | 30 +++++++++----- .../reference/conditionalTypes1.symbols | 37 +++++++++++++----- .../reference/conditionalTypes1.types | 39 ++++++++++++++----- 4 files changed, 87 insertions(+), 35 deletions(-) diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index 8016c4449d3e4..a7717d182631c 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -304,12 +304,12 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2 type And = If; type Or = If; - type isString = Extends; + type IsString = Extends; - type Q1 = isString; // false - type Q2 = isString<"abc">; // true - type Q3 = isString; // boolean - type Q4 = isString; // boolean + type Q1 = IsString; // false + type Q2 = IsString<"abc">; // true + type Q3 = IsString; // boolean + type Q4 = IsString; // boolean type N1 = Not; // true type N2 = Not; // false @@ -338,4 +338,10 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2 type T40 = never extends never ? true : false; // true type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean + + type IsNever = T extends never ? true : false; + + type T50 = IsNever; // true + type T51 = IsNever; // false + type T52 = IsNever; // false \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes1.js b/tests/baselines/reference/conditionalTypes1.js index 088181b3b1241..0da7794a76214 100644 --- a/tests/baselines/reference/conditionalTypes1.js +++ b/tests/baselines/reference/conditionalTypes1.js @@ -164,12 +164,12 @@ type Not = If; type And = If; type Or = If; -type isString = Extends; +type IsString = Extends; -type Q1 = isString; // false -type Q2 = isString<"abc">; // true -type Q3 = isString; // boolean -type Q4 = isString; // boolean +type Q1 = IsString; // false +type Q2 = IsString<"abc">; // true +type Q3 = IsString; // boolean +type Q4 = IsString; // boolean type N1 = Not; // true type N2 = Not; // false @@ -198,6 +198,12 @@ type O9 = Or; // boolean type T40 = never extends never ? true : false; // true type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean + +type IsNever = T extends never ? true : false; + +type T50 = IsNever; // true +type T51 = IsNever; // false +type T52 = IsNever; // false //// [conditionalTypes1.js] @@ -376,11 +382,11 @@ declare type If = C extends true ? T : F; declare type Not = If; declare type And = If; declare type Or = If; -declare type isString = Extends; -declare type Q1 = isString; -declare type Q2 = isString<"abc">; -declare type Q3 = isString; -declare type Q4 = isString; +declare type IsString = Extends; +declare type Q1 = IsString; +declare type Q2 = IsString<"abc">; +declare type Q3 = IsString; +declare type Q4 = IsString; declare type N1 = Not; declare type N2 = Not; declare type N3 = Not; @@ -405,3 +411,7 @@ declare type O9 = Or; declare type T40 = never extends never ? true : false; declare type T41 = number extends never ? true : false; declare type T42 = never extends number ? true : false; +declare type IsNever = T extends never ? true : false; +declare type T50 = IsNever; +declare type T51 = IsNever; +declare type T52 = IsNever; diff --git a/tests/baselines/reference/conditionalTypes1.symbols b/tests/baselines/reference/conditionalTypes1.symbols index ab0426f67d539..9d3b79d5c30a0 100644 --- a/tests/baselines/reference/conditionalTypes1.symbols +++ b/tests/baselines/reference/conditionalTypes1.symbols @@ -645,27 +645,27 @@ type Or = If; >A : Symbol(A, Decl(conditionalTypes1.ts, 163, 8)) >B : Symbol(B, Decl(conditionalTypes1.ts, 163, 26)) -type isString = Extends; ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +type IsString = Extends; +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) >T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14)) >Extends : Symbol(Extends, Decl(conditionalTypes1.ts, 157, 1)) >T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14)) -type Q1 = isString; // false +type Q1 = IsString; // false >Q1 : Symbol(Q1, Decl(conditionalTypes1.ts, 165, 38)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) -type Q2 = isString<"abc">; // true +type Q2 = IsString<"abc">; // true >Q2 : Symbol(Q2, Decl(conditionalTypes1.ts, 167, 27)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) -type Q3 = isString; // boolean +type Q3 = IsString; // boolean >Q3 : Symbol(Q3, Decl(conditionalTypes1.ts, 168, 26)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) -type Q4 = isString; // boolean +type Q4 = IsString; // boolean >Q4 : Symbol(Q4, Decl(conditionalTypes1.ts, 169, 24)) ->isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63)) type N1 = Not; // true >N1 : Symbol(N1, Decl(conditionalTypes1.ts, 170, 26)) @@ -760,3 +760,20 @@ type T41 = number extends never ? true : false; // false type T42 = never extends number ? true : false; // boolean >T42 : Symbol(T42, Decl(conditionalTypes1.ts, 197, 47)) +type IsNever = T extends never ? true : false; +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 200, 13)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 200, 13)) + +type T50 = IsNever; // true +>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 200, 49)) +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) + +type T51 = IsNever; // false +>T51 : Symbol(T51, Decl(conditionalTypes1.ts, 202, 26)) +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) + +type T52 = IsNever; // false +>T52 : Symbol(T52, Decl(conditionalTypes1.ts, 203, 27)) +>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47)) + diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 9fc72f368d5a6..df825ecd40b7d 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -717,27 +717,27 @@ type Or = If; >true : true >B : B -type isString = Extends; ->isString : Extends +type IsString = Extends; +>IsString : Extends >T : T >Extends : Extends >T : T -type Q1 = isString; // false +type Q1 = IsString; // false >Q1 : false ->isString : Extends +>IsString : Extends -type Q2 = isString<"abc">; // true +type Q2 = IsString<"abc">; // true >Q2 : true ->isString : Extends +>IsString : Extends -type Q3 = isString; // boolean +type Q3 = IsString; // boolean >Q3 : boolean ->isString : Extends +>IsString : Extends -type Q4 = isString; // boolean +type Q4 = IsString; // boolean >Q4 : boolean ->isString : Extends +>IsString : Extends type N1 = Not; // true >N1 : true @@ -864,3 +864,22 @@ type T42 = never extends number ? true : false; // boolean >true : true >false : false +type IsNever = T extends never ? true : false; +>IsNever : IsNever +>T : T +>T : T +>true : true +>false : false + +type T50 = IsNever; // true +>T50 : true +>IsNever : IsNever + +type T51 = IsNever; // false +>T51 : false +>IsNever : IsNever + +type T52 = IsNever; // false +>T52 : false +>IsNever : IsNever +