From 61f0736f5535beddab9dcca6b2d40247a2567ef0 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 12 Apr 2019 14:48:46 -0700 Subject: [PATCH 1/3] Optimize variance checking during identity checking --- src/compiler/checker.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7becc4a2f78c6..26397e05b188a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10250,7 +10250,7 @@ namespace ts { function getConditionalTypeWorker(root: ConditionalRoot, mapper: TypeMapper | undefined, checkType: Type, extendsType: Type, trueType: Type, falseType: Type) { // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`. - if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) { + if (falseType.flags & TypeFlags.Never && isTypeIdenticalTo(getActualTypeVariable(trueType), getActualTypeVariable(checkType))) { if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true return trueType; } @@ -10258,7 +10258,7 @@ namespace ts { return neverType; } } - else if (trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType)) { + else if (trueType.flags & TypeFlags.Never && isTypeIdenticalTo(getActualTypeVariable(falseType), getActualTypeVariable(checkType))) { if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true return neverType; } @@ -12840,7 +12840,7 @@ namespace ts { if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { - const variances = getAliasVariances(source.aliasSymbol); + const variances = relation === identityRelation ? emptyArray : getAliasVariances(source.aliasSymbol); const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances); if (varianceResult !== undefined) { return varianceResult; @@ -13023,7 +13023,7 @@ namespace ts { // We have type references to the same generic type, and the type references are not marker // type references (which are intended by be compared structurally). Obtain the variance // information for the type parameters and relate the type arguments accordingly. - const variances = getVariances((source).target); + const variances = relation === identityRelation ? emptyArray : getVariances((source).target); const varianceResult = relateVariances((source).typeArguments, (target).typeArguments, variances); if (varianceResult !== undefined) { return varianceResult; @@ -13082,6 +13082,9 @@ namespace ts { if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) { return result; } + if (relation === identityRelation) { + return result; + } const allowStructuralFallback = (targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances)) || isNonGeneric(source) || isNonGeneric(target); varianceCheckFailed = !allowStructuralFallback; // The type arguments did not relate appropriately, but it may be because we have no variance From 0923a7cad5546f58f39ac785650562bdf4a1fb55 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 12 Apr 2019 15:19:02 -0700 Subject: [PATCH 2/3] Accept good (!??!) baseline changes --- .../newOperatorConformance.errors.txt | 68 +++++++++++++++++++ .../newOperatorErrorCases.errors.txt | 5 +- ...wrappedAndRecursiveConstraints2.errors.txt | 12 ++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/newOperatorConformance.errors.txt create mode 100644 tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt diff --git a/tests/baselines/reference/newOperatorConformance.errors.txt b/tests/baselines/reference/newOperatorConformance.errors.txt new file mode 100644 index 0000000000000..d92b3527ab7c4 --- /dev/null +++ b/tests/baselines/reference/newOperatorConformance.errors.txt @@ -0,0 +1,68 @@ +tests/cases/conformance/expressions/newOperator/newOperatorConformance.ts(32,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. + + +==== tests/cases/conformance/expressions/newOperator/newOperatorConformance.ts (1 errors) ==== + class C0 { + + } + class C1 { + constructor(n: number, s: string) { } + } + + class T { + constructor(n?: T) { } + } + + var anyCtor: { + new (): any; + }; + + var anyCtor1: { + new (n): any; + }; + + interface nestedCtor { + new (): nestedCtor; + } + var nestedCtor: nestedCtor; + + // Construct expression with no parentheses for construct signature with 0 parameters + var a = new C0; + var a: C0; + + + // Generic construct expression with no parentheses + var c1 = new T; + var c1: T<{}>; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. + + // Construct expression where constructor is of type 'any' with no parentheses + var d = new anyCtor; + var d: any; + + // Construct expression where constructor is of type 'any' with > 1 arg + var d = new anyCtor1(undefined); + + // Construct expression of type where apparent type has a construct signature with 0 arguments + function newFn1(s: T) { + var p = new s; + var p: number; + } + + // Construct expression of type where apparent type has a construct signature with 1 arguments + function newFn2(s: T) { + var p = new s(32); + var p: string; + } + + // Construct expression of void returning function + function fnVoid(): void { } + var t = new fnVoid(); + var t: any; + + // Chained new expressions + var nested = new (new (new nestedCtor())())(); + var n = new nested(); + var n = new nested(); + \ No newline at end of file diff --git a/tests/baselines/reference/newOperatorErrorCases.errors.txt b/tests/baselines/reference/newOperatorErrorCases.errors.txt index c41efaac28995..7a5a9da056402 100644 --- a/tests/baselines/reference/newOperatorErrorCases.errors.txt +++ b/tests/baselines/reference/newOperatorErrorCases.errors.txt @@ -1,10 +1,11 @@ tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(26,16): error TS1005: ',' expected. tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(26,16): error TS2695: Left side of comma operator is unused and has no side effects. +tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(30,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(31,23): error TS1005: '(' expected. tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(36,9): error TS2350: Only a void function can be called with the 'new' keyword. -==== tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts (4 errors) ==== +==== tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts (5 errors) ==== class C0 { } @@ -39,6 +40,8 @@ tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(36,9): // Generic construct expression with no parentheses var c1 = new T; var c1: T<{}>; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. var c2 = new T; // Parse error ~ !!! error TS1005: '(' expected. diff --git a/tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt b/tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt new file mode 100644 index 0000000000000..a443e72497b3f --- /dev/null +++ b/tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints2.ts(6,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'C', but here has type 'C>'. + + +==== tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints2.ts (1 errors) ==== + class C> { // error + constructor(x: T) { } + } + + var c = new C(1); + var c = new C(new C('')); // error + ~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'C', but here has type 'C>'. \ No newline at end of file From 637d0b6f7a9fe77bf861875f3b463ac2eb34b36d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 12 Apr 2019 15:29:04 -0700 Subject: [PATCH 3/3] Walk back initial change a bit to prevent baseline changes --- src/compiler/checker.ts | 4 +- .../newOperatorConformance.errors.txt | 68 ------------------- .../newOperatorErrorCases.errors.txt | 5 +- ...wrappedAndRecursiveConstraints2.errors.txt | 12 ---- 4 files changed, 3 insertions(+), 86 deletions(-) delete mode 100644 tests/baselines/reference/newOperatorConformance.errors.txt delete mode 100644 tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26397e05b188a..9002ddeb18644 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12840,7 +12840,7 @@ namespace ts { if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { - const variances = relation === identityRelation ? emptyArray : getAliasVariances(source.aliasSymbol); + const variances = getAliasVariances(source.aliasSymbol); const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances); if (varianceResult !== undefined) { return varianceResult; @@ -13023,7 +13023,7 @@ namespace ts { // We have type references to the same generic type, and the type references are not marker // type references (which are intended by be compared structurally). Obtain the variance // information for the type parameters and relate the type arguments accordingly. - const variances = relation === identityRelation ? emptyArray : getVariances((source).target); + const variances = getVariances((source).target); const varianceResult = relateVariances((source).typeArguments, (target).typeArguments, variances); if (varianceResult !== undefined) { return varianceResult; diff --git a/tests/baselines/reference/newOperatorConformance.errors.txt b/tests/baselines/reference/newOperatorConformance.errors.txt deleted file mode 100644 index d92b3527ab7c4..0000000000000 --- a/tests/baselines/reference/newOperatorConformance.errors.txt +++ /dev/null @@ -1,68 +0,0 @@ -tests/cases/conformance/expressions/newOperator/newOperatorConformance.ts(32,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. - - -==== tests/cases/conformance/expressions/newOperator/newOperatorConformance.ts (1 errors) ==== - class C0 { - - } - class C1 { - constructor(n: number, s: string) { } - } - - class T { - constructor(n?: T) { } - } - - var anyCtor: { - new (): any; - }; - - var anyCtor1: { - new (n): any; - }; - - interface nestedCtor { - new (): nestedCtor; - } - var nestedCtor: nestedCtor; - - // Construct expression with no parentheses for construct signature with 0 parameters - var a = new C0; - var a: C0; - - - // Generic construct expression with no parentheses - var c1 = new T; - var c1: T<{}>; - ~~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. - - // Construct expression where constructor is of type 'any' with no parentheses - var d = new anyCtor; - var d: any; - - // Construct expression where constructor is of type 'any' with > 1 arg - var d = new anyCtor1(undefined); - - // Construct expression of type where apparent type has a construct signature with 0 arguments - function newFn1(s: T) { - var p = new s; - var p: number; - } - - // Construct expression of type where apparent type has a construct signature with 1 arguments - function newFn2(s: T) { - var p = new s(32); - var p: string; - } - - // Construct expression of void returning function - function fnVoid(): void { } - var t = new fnVoid(); - var t: any; - - // Chained new expressions - var nested = new (new (new nestedCtor())())(); - var n = new nested(); - var n = new nested(); - \ No newline at end of file diff --git a/tests/baselines/reference/newOperatorErrorCases.errors.txt b/tests/baselines/reference/newOperatorErrorCases.errors.txt index 7a5a9da056402..c41efaac28995 100644 --- a/tests/baselines/reference/newOperatorErrorCases.errors.txt +++ b/tests/baselines/reference/newOperatorErrorCases.errors.txt @@ -1,11 +1,10 @@ tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(26,16): error TS1005: ',' expected. tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(26,16): error TS2695: Left side of comma operator is unused and has no side effects. -tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(30,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(31,23): error TS1005: '(' expected. tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(36,9): error TS2350: Only a void function can be called with the 'new' keyword. -==== tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts (5 errors) ==== +==== tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts (4 errors) ==== class C0 { } @@ -40,8 +39,6 @@ tests/cases/conformance/expressions/newOperator/newOperatorErrorCases.ts(36,9): // Generic construct expression with no parentheses var c1 = new T; var c1: T<{}>; - ~~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c1' must be of type 'T', but here has type 'T<{}>'. var c2 = new T; // Parse error ~ !!! error TS1005: '(' expected. diff --git a/tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt b/tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt deleted file mode 100644 index a443e72497b3f..0000000000000 --- a/tests/baselines/reference/wrappedAndRecursiveConstraints2.errors.txt +++ /dev/null @@ -1,12 +0,0 @@ -tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints2.ts(6,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'C', but here has type 'C>'. - - -==== tests/cases/conformance/types/typeParameters/typeArgumentLists/wrappedAndRecursiveConstraints2.ts (1 errors) ==== - class C> { // error - constructor(x: T) { } - } - - var c = new C(1); - var c = new C(new C('')); // error - ~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'C', but here has type 'C>'. \ No newline at end of file