From 815e7926f43b85e5bdbd86e777c561bc16a1ba16 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 19 Feb 2019 16:07:20 -0800 Subject: [PATCH 01/10] Use identity with the restrictive instantation to detect nongenric instances and disable variance probing on nongeneric instances --- src/compiler/checker.ts | 1 + .../mappedTypeRelationships.errors.txt | 4 - .../strictFunctionTypesErrors.errors.txt | 86 +++++++++++++------ ...unionTypeErrorMessageTypeRefs01.errors.txt | 18 ++-- ...derIndexSignatureRelationsAlign.errors.txt | 82 ------------------ ...eroOrderIndexSignatureRelationsAlign.types | 2 +- ...erIndexSignatureRelationsAlign2.errors.txt | 79 ----------------- 7 files changed, 74 insertions(+), 198 deletions(-) delete mode 100644 tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.errors.txt delete mode 100644 tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ac19fb98d060..e756caa38d773 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12603,6 +12603,7 @@ namespace ts { // the order in which things were checked. if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && + !isTypeIdenticalTo(getRestrictiveInstantiation(source), source) && !isTypeIdenticalTo(getRestrictiveInstantiation(target), target) && !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { const variances = getAliasVariances(source.aliasSymbol); const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances); diff --git a/tests/baselines/reference/mappedTypeRelationships.errors.txt b/tests/baselines/reference/mappedTypeRelationships.errors.txt index 3d63765407972..60a06e000c255 100644 --- a/tests/baselines/reference/mappedTypeRelationships.errors.txt +++ b/tests/baselines/reference/mappedTypeRelationships.errors.txt @@ -34,9 +34,7 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2 tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2542: Index signature in type 'Readonly' only permits reading. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(72,5): error TS2322: Type 'Partial' is not assignable to type 'T'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(78,5): error TS2322: Type 'Partial' is not assignable to type 'Partial'. - Type 'Thing' is not assignable to type 'T'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(88,5): error TS2322: Type 'Readonly' is not assignable to type 'Readonly'. - Type 'Thing' is not assignable to type 'T'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(127,5): error TS2322: Type 'Partial' is not assignable to type 'Identity'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(143,5): error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'. Type 'T[P]' is not assignable to type 'U[P]'. @@ -199,7 +197,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS y = x; // Error ~ !!! error TS2322: Type 'Partial' is not assignable to type 'Partial'. -!!! error TS2322: Type 'Thing' is not assignable to type 'T'. } function f40(x: T, y: Readonly) { @@ -212,7 +209,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS y = x; // Error ~ !!! error TS2322: Type 'Readonly' is not assignable to type 'Readonly'. -!!! error TS2322: Type 'Thing' is not assignable to type 'T'. } type Item = { diff --git a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt index 3ff04c44fb75b..21f4bc58cff92 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt +++ b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt @@ -17,15 +17,19 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(21,1): error TS2322: Type '(x: tests/cases/compiler/strictFunctionTypesErrors.ts(23,1): error TS2322: Type '(x: string) => Object' is not assignable to type '(x: string) => string'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(33,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(34,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(36,1): error TS2322: Type 'Func' is not assignable to type 'Func'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(37,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(38,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(44,1): error TS2322: Type 'Func' is not assignable to type 'Func'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(46,1): error TS2322: Type 'Func' is not assignable to type 'Func'. @@ -35,26 +39,39 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(57,1): error TS2322: Type 'Fun tests/cases/compiler/strictFunctionTypesErrors.ts(58,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(61,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. - Type 'Func' is not assignable to type 'Func'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(62,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. - Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(65,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. - Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(66,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. - Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(67,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(74,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(75,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(76,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(79,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(80,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Type 'Object' is not assignable to type 'string'. + Types of parameters 'x' and 'x' are incompatible. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(83,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. @@ -147,11 +164,13 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c g1 = g3; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g1 = g4; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g2 = g1; // Error ~~ @@ -160,11 +179,13 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c g2 = g3; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g2 = g4; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g3 = g1; // Ok g3 = g2; // Ok @@ -202,22 +223,29 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c h3 = h1; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h3 = h2; // Error ~~ !!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h3 = h4; // Ok h4 = h1; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h4 = h2; // Error ~~ !!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. -!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h4 = h3; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. @@ -232,24 +260,30 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. !!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i1 = i3; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i1 = i4; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i2 = i1; // Ok i2 = i3; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i2 = i4; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i3 = i1; // Ok i3 = i2; // Error diff --git a/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt b/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt index ab661b6fee7c8..5fdeab58610af 100644 --- a/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt +++ b/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt @@ -9,13 +9,16 @@ tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(27,1): error TS2322: Typ Property 'kwah' is missing in type 'Foo' but required in type 'Kwah'. tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(48,1): error TS2322: Type 'X' is not assignable to type 'X | Y | Z'. Type 'X' is not assignable to type 'X'. - Type 'Foo' is not assignable to type 'Bar'. + Types of property 'xProp' are incompatible. + Type 'Foo' is not assignable to type 'Bar'. tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(49,1): error TS2322: Type 'Y' is not assignable to type 'X | Y | Z'. Type 'Y' is not assignable to type 'Y'. - Type 'Foo' is not assignable to type 'Baz'. + Types of property 'yProp' are incompatible. + Type 'Foo' is not assignable to type 'Baz'. tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(50,1): error TS2322: Type 'Z' is not assignable to type 'X | Y | Z'. Type 'Z' is not assignable to type 'Z'. - Type 'Foo' is not assignable to type 'Kwah'. + Types of property 'zProp' are incompatible. + Type 'Foo' is not assignable to type 'Kwah'. ==== tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts (6 errors) ==== @@ -85,14 +88,17 @@ tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(50,1): error TS2322: Typ ~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type 'X' is not assignable to type 'X | Y | Z'. !!! error TS2322: Type 'X' is not assignable to type 'X'. -!!! error TS2322: Type 'Foo' is not assignable to type 'Bar'. +!!! error TS2322: Types of property 'xProp' are incompatible. +!!! error TS2322: Type 'Foo' is not assignable to type 'Bar'. thingOfTypeAliases = y; ~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type 'Y' is not assignable to type 'X | Y | Z'. !!! error TS2322: Type 'Y' is not assignable to type 'Y'. -!!! error TS2322: Type 'Foo' is not assignable to type 'Baz'. +!!! error TS2322: Types of property 'yProp' are incompatible. +!!! error TS2322: Type 'Foo' is not assignable to type 'Baz'. thingOfTypeAliases = z; ~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type 'Z' is not assignable to type 'X | Y | Z'. !!! error TS2322: Type 'Z' is not assignable to type 'Z'. -!!! error TS2322: Type 'Foo' is not assignable to type 'Kwah'. \ No newline at end of file +!!! error TS2322: Types of property 'zProp' are incompatible. +!!! error TS2322: Type 'Foo' is not assignable to type 'Kwah'. \ No newline at end of file diff --git a/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.errors.txt b/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.errors.txt deleted file mode 100644 index 47f97958f0d53..0000000000000 --- a/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.errors.txt +++ /dev/null @@ -1,82 +0,0 @@ -tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts(63,6): error TS2345: Argument of type 'NeededInfo>' is not assignable to parameter of type 'NeededInfo<{}>'. - Types of property 'ASchema' are incompatible. - Type 'ToA>' is not assignable to type 'ToA<{}>'. - Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'. -tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts(66,38): error TS2344: Type 'NeededInfo>' does not satisfy the constraint 'NeededInfo<{}>'. - - -==== tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts (2 errors) ==== - type Either = Left | Right; - - class Left { - readonly _tag: 'Left' = 'Left' - readonly _A!: A - readonly _L!: L - constructor(readonly value: L) {} - /** The given function is applied if this is a `Right` */ - map(f: (a: A) => B): Either { - return this as any - } - ap(fab: Either B>): Either { - return null as any - } - } - - class Right { - readonly _tag: 'Right' = 'Right' - readonly _A!: A - readonly _L!: L - constructor(readonly value: A) {} - map(f: (a: A) => B): Either { - return new Right(f(this.value)) - } - ap(fab: Either B>): Either { - return null as any; - } - } - - class Type { - readonly _A!: A; - readonly _O!: O; - readonly _I!: I; - constructor( - /** a unique name for this codec */ - readonly name: string, - /** a custom type guard */ - readonly is: (u: unknown) => u is A, - /** succeeds if a value of type I can be decoded to a value of type A */ - readonly validate: (input: I, context: {}[]) => Either<{}[], A>, - /** converts a value of type A to a value of type O */ - readonly encode: (a: A) => O - ) {} - /** a version of `validate` with a default context */ - decode(i: I): Either<{}[], A> { return null as any; } - } - - interface Any extends Type {} - - type TypeOf = C["_A"]; - - type ToB = { [k in keyof S]: TypeOf }; - type ToA = { [k in keyof S]: Type }; - - type NeededInfo = { - ASchema: ToA; - }; - - export type MyInfo = NeededInfo>; - - const tmp1: MyInfo = null!; - function tmp2(n: N) {} - tmp2(tmp1); // uncommenting this line removes a type error from a completely unrelated line ?? - ~~~~ -!!! error TS2345: Argument of type 'NeededInfo>' is not assignable to parameter of type 'NeededInfo<{}>'. -!!! error TS2345: Types of property 'ASchema' are incompatible. -!!! error TS2345: Type 'ToA>' is not assignable to type 'ToA<{}>'. -!!! error TS2345: Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'. -!!! related TS2728 tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.ts:59:39: 'initialize' is declared here. - - class Server {} - export class MyServer extends Server {} // not assignable error at `MyInfo` - ~~~~~~ -!!! error TS2344: Type 'NeededInfo>' does not satisfy the constraint 'NeededInfo<{}>'. \ No newline at end of file diff --git a/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.types b/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.types index d360372d5aaee..f6342d442ee2f 100644 --- a/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.types +++ b/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign.types @@ -155,7 +155,7 @@ function tmp2(n: N) {} >n : N tmp2(tmp1); // uncommenting this line removes a type error from a completely unrelated line ?? ->tmp2(tmp1) : any +>tmp2(tmp1) : void >tmp2 : >(n: N) => void >tmp1 : NeededInfo> diff --git a/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.errors.txt b/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.errors.txt deleted file mode 100644 index aba1bc1db66d9..0000000000000 --- a/tests/baselines/reference/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.errors.txt +++ /dev/null @@ -1,79 +0,0 @@ -tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.ts(66,38): error TS2344: Type 'NeededInfo>' does not satisfy the constraint 'NeededInfo<{}>'. - Types of property 'ASchema' are incompatible. - Type 'ToA>' is not assignable to type 'ToA<{}>'. - Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'. - - -==== tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.ts (1 errors) ==== - type Either = Left | Right; - - class Left { - readonly _tag: 'Left' = 'Left' - readonly _A!: A - readonly _L!: L - constructor(readonly value: L) {} - /** The given function is applied if this is a `Right` */ - map(f: (a: A) => B): Either { - return this as any - } - ap(fab: Either B>): Either { - return null as any - } - } - - class Right { - readonly _tag: 'Right' = 'Right' - readonly _A!: A - readonly _L!: L - constructor(readonly value: A) {} - map(f: (a: A) => B): Either { - return new Right(f(this.value)) - } - ap(fab: Either B>): Either { - return null as any; - } - } - - class Type { - readonly _A!: A; - readonly _O!: O; - readonly _I!: I; - constructor( - /** a unique name for this codec */ - readonly name: string, - /** a custom type guard */ - readonly is: (u: unknown) => u is A, - /** succeeds if a value of type I can be decoded to a value of type A */ - readonly validate: (input: I, context: {}[]) => Either<{}[], A>, - /** converts a value of type A to a value of type O */ - readonly encode: (a: A) => O - ) {} - /** a version of `validate` with a default context */ - decode(i: I): Either<{}[], A> { return null as any; } - } - - interface Any extends Type {} - - type TypeOf = C["_A"]; - - type ToB = { [k in keyof S]: TypeOf }; - type ToA = { [k in keyof S]: Type }; - - type NeededInfo = { - ASchema: ToA; - }; - - export type MyInfo = NeededInfo>; - - const tmp1: MyInfo = null!; - function tmp2(n: N) {} - // tmp2(tmp1); // uncommenting this line removes a type error from a completely unrelated line ?? (see test 1, needs to behave the same) - - class Server {} - export class MyServer extends Server {} // not assignable error at `MyInfo` - ~~~~~~ -!!! error TS2344: Type 'NeededInfo>' does not satisfy the constraint 'NeededInfo<{}>'. -!!! error TS2344: Types of property 'ASchema' are incompatible. -!!! error TS2344: Type 'ToA>' is not assignable to type 'ToA<{}>'. -!!! error TS2344: Type '{}' is not assignable to type 'ToB<{ initialize: any; }>'. -!!! related TS2728 tests/cases/compiler/varianceProblingAndZeroOrderIndexSignatureRelationsAlign2.ts:59:39: 'initialize' is declared here. \ No newline at end of file From 579066d39dab73cb76a94276e737ca29b62508e2 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 25 Feb 2019 15:33:25 -0800 Subject: [PATCH 02/10] Generalize to also include interfaces, add test case, still perform argument comparisons for postive comparisons if possible --- src/compiler/checker.ts | 11 +++-- ...eckInfiniteExpansionTermination.errors.txt | 32 -------------- ...alInstantiationsRelatedInBothDirections.js | 18 ++++++++ ...tantiationsRelatedInBothDirections.symbols | 43 +++++++++++++++++++ ...nstantiationsRelatedInBothDirections.types | 33 ++++++++++++++ ...alInstantiationsRelatedInBothDirections.ts | 12 ++++++ 6 files changed, 113 insertions(+), 36 deletions(-) delete mode 100644 tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt create mode 100644 tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.js create mode 100644 tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.symbols create mode 100644 tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.types create mode 100644 tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ca8d8082e8141..65728d600a524 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12603,7 +12603,6 @@ namespace ts { // the order in which things were checked. if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && - !isTypeIdenticalTo(getRestrictiveInstantiation(source), source) && !isTypeIdenticalTo(getRestrictiveInstantiation(target), target) && !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { const variances = getAliasVariances(source.aliasSymbol); const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances); @@ -12813,12 +12812,16 @@ namespace ts { } return Ternary.False; + function isNonGeneric(type: Type) { + return isTypeIdenticalTo(getRestrictiveInstantiation(type), type); + } + function relateVariances(sourceTypeArguments: ReadonlyArray | undefined, targetTypeArguments: ReadonlyArray | undefined, variances: Variance[]) { if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) { return result; } - const isCovariantVoid = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances); - varianceCheckFailed = !isCovariantVoid; + 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 // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type // arguments). It might also be the case that the target type has a 'void' type argument for @@ -12826,7 +12829,7 @@ namespace ts { // (in which case any type argument is permitted on the source side). In those cases we proceed // with a structural comparison. Otherwise, we know for certain the instantiations aren't // related and we can return here. - if (variances !== emptyArray && !isCovariantVoid) { + if (variances !== emptyArray && !allowStructuralFallback) { // In some cases generic types that are covariant in regular type checking mode become // invariant in --strictFunctionTypes mode because one or more type parameters are used in // both co- and contravariant positions. In order to make it easier to diagnose *why* such diff --git a/tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt b/tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt deleted file mode 100644 index 014087ff6275e..0000000000000 --- a/tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt +++ /dev/null @@ -1,32 +0,0 @@ -tests/cases/compiler/checkInfiniteExpansionTermination.ts(16,1): error TS2322: Type 'ISubject' is not assignable to type 'IObservable'. - Types of property 'n' are incompatible. - Type 'IObservable' is not assignable to type 'IObservable'. - Type 'Bar[]' is not assignable to type 'Foo[]'. - Property 'x' is missing in type 'Bar' but required in type 'Foo'. - - -==== tests/cases/compiler/checkInfiniteExpansionTermination.ts (1 errors) ==== - // Regression test for #1002 - // Before fix this code would cause infinite loop - - interface IObservable { - n: IObservable; // Needed, must be T[] - } - - // Needed - interface ISubject extends IObservable { } - - interface Foo { x } - interface Bar { y } - - var values: IObservable; - var values2: ISubject; - values = values2; - ~~~~~~ -!!! error TS2322: Type 'ISubject' is not assignable to type 'IObservable'. -!!! error TS2322: Types of property 'n' are incompatible. -!!! error TS2322: Type 'IObservable' is not assignable to type 'IObservable'. -!!! error TS2322: Type 'Bar[]' is not assignable to type 'Foo[]'. -!!! error TS2322: Property 'x' is missing in type 'Bar' but required in type 'Foo'. -!!! related TS2728 tests/cases/compiler/checkInfiniteExpansionTermination.ts:11:17: 'x' is declared here. - \ No newline at end of file diff --git a/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.js b/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.js new file mode 100644 index 0000000000000..630adb92c4312 --- /dev/null +++ b/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.js @@ -0,0 +1,18 @@ +//// [nongenericPartialInstantiationsRelatedInBothDirections.ts] +interface Foo { + a: number; + b: number; + bar: string; +} +interface ObjectContaining { + new (sample: Partial): Partial +} +declare let cafoo: ObjectContaining<{ a: number, foo: number }>; +declare let cfoo: ObjectContaining; +cfoo = cafoo; +cafoo = cfoo; + + +//// [nongenericPartialInstantiationsRelatedInBothDirections.js] +cfoo = cafoo; +cafoo = cfoo; diff --git a/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.symbols b/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.symbols new file mode 100644 index 0000000000000..ee61fa0fd88d9 --- /dev/null +++ b/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.symbols @@ -0,0 +1,43 @@ +=== tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 15)) + + b: number; +>b : Symbol(Foo.b, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 1, 14)) + + bar: string; +>bar : Symbol(Foo.bar, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 2, 14)) +} +interface ObjectContaining { +>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1)) +>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27)) + + new (sample: Partial): Partial +>sample : Symbol(sample, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 6, 7)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27)) +} +declare let cafoo: ObjectContaining<{ a: number, foo: number }>; +>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11)) +>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1)) +>a : Symbol(a, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 37)) +>foo : Symbol(foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 48)) + +declare let cfoo: ObjectContaining; +>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11)) +>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1)) +>Foo : Symbol(Foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 0)) + +cfoo = cafoo; +>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11)) +>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11)) + +cafoo = cfoo; +>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11)) +>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11)) + diff --git a/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.types b/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.types new file mode 100644 index 0000000000000..cbce9ce867b4d --- /dev/null +++ b/tests/baselines/reference/nongenericPartialInstantiationsRelatedInBothDirections.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts === +interface Foo { + a: number; +>a : number + + b: number; +>b : number + + bar: string; +>bar : string +} +interface ObjectContaining { + new (sample: Partial): Partial +>sample : Partial +} +declare let cafoo: ObjectContaining<{ a: number, foo: number }>; +>cafoo : ObjectContaining<{ a: number; foo: number; }> +>a : number +>foo : number + +declare let cfoo: ObjectContaining; +>cfoo : ObjectContaining + +cfoo = cafoo; +>cfoo = cafoo : ObjectContaining<{ a: number; foo: number; }> +>cfoo : ObjectContaining +>cafoo : ObjectContaining<{ a: number; foo: number; }> + +cafoo = cfoo; +>cafoo = cfoo : ObjectContaining +>cafoo : ObjectContaining<{ a: number; foo: number; }> +>cfoo : ObjectContaining + diff --git a/tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts b/tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts new file mode 100644 index 0000000000000..ece5187738c60 --- /dev/null +++ b/tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts @@ -0,0 +1,12 @@ +interface Foo { + a: number; + b: number; + bar: string; +} +interface ObjectContaining { + new (sample: Partial): Partial +} +declare let cafoo: ObjectContaining<{ a: number, foo: number }>; +declare let cfoo: ObjectContaining; +cfoo = cafoo; +cafoo = cfoo; From cd92006b00e28dff59040614fd276d838fe41b27 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 25 Feb 2019 15:55:26 -0800 Subject: [PATCH 03/10] Actually accept baselines, lol --- ...nvariantGenericErrorElaboration.errors.txt | 52 --------- .../invariantGenericErrorElaboration.types | 4 +- .../recursiveTypeComparison.errors.txt | 27 ----- .../strictFunctionTypesErrors.errors.txt | 102 ++++++------------ ...unionTypeErrorMessageTypeRefs01.errors.txt | 18 ++-- 5 files changed, 38 insertions(+), 165 deletions(-) delete mode 100644 tests/baselines/reference/invariantGenericErrorElaboration.errors.txt delete mode 100644 tests/baselines/reference/recursiveTypeComparison.errors.txt diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt b/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt deleted file mode 100644 index 0bd79bcf11d6a..0000000000000 --- a/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt +++ /dev/null @@ -1,52 +0,0 @@ -tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype'. - Types of property 'constraint' are incompatible. - Type 'Constraint' is not assignable to type 'Constraint>'. - Types of property 'constraint' are incompatible. - Type 'Constraint>' is not assignable to type 'Constraint>>'. - Types of property 'constraint' are incompatible. - Type 'Constraint>>' is not assignable to type 'Constraint>>>'. - Type 'Constraint>>' is not assignable to type 'Constraint>'. - Types of property 'underlying' are incompatible. - Type 'Constraint>' is not assignable to type 'Constraint'. -tests/cases/compiler/invariantGenericErrorElaboration.ts(4,19): error TS2322: Type 'Num' is not assignable to type 'Runtype'. - - -==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ==== - // Repro from #19746 - - const wat: Runtype = Num; - ~~~ -!!! error TS2322: Type 'Num' is not assignable to type 'Runtype'. -!!! error TS2322: Types of property 'constraint' are incompatible. -!!! error TS2322: Type 'Constraint' is not assignable to type 'Constraint>'. -!!! error TS2322: Types of property 'constraint' are incompatible. -!!! error TS2322: Type 'Constraint>' is not assignable to type 'Constraint>>'. -!!! error TS2322: Types of property 'constraint' are incompatible. -!!! error TS2322: Type 'Constraint>>' is not assignable to type 'Constraint>>>'. -!!! error TS2322: Type 'Constraint>>' is not assignable to type 'Constraint>'. -!!! error TS2322: Types of property 'underlying' are incompatible. -!!! error TS2322: Type 'Constraint>' is not assignable to type 'Constraint'. -!!! related TS2728 tests/cases/compiler/invariantGenericErrorElaboration.ts:12:3: 'tag' is declared here. - const Foo = Obj({ foo: Num }) - ~~~ -!!! error TS2322: Type 'Num' is not assignable to type 'Runtype'. -!!! related TS6501 tests/cases/compiler/invariantGenericErrorElaboration.ts:17:34: The expected type comes from this index signature. - - interface Runtype { - constraint: Constraint - witness: A - } - - interface Num extends Runtype { - tag: 'number' - } - declare const Num: Num - - interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} - declare function Obj }>(fields: O): Obj; - - interface Constraint> extends Runtype { - underlying: A, - check: (x: A['witness']) => void, - } - \ No newline at end of file diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.types b/tests/baselines/reference/invariantGenericErrorElaboration.types index 7c4bdd46d037f..86aec86face81 100644 --- a/tests/baselines/reference/invariantGenericErrorElaboration.types +++ b/tests/baselines/reference/invariantGenericErrorElaboration.types @@ -6,8 +6,8 @@ const wat: Runtype = Num; >Num : Num const Foo = Obj({ foo: Num }) ->Foo : any ->Obj({ foo: Num }) : any +>Foo : Obj<{ foo: Num; }> +>Obj({ foo: Num }) : Obj<{ foo: Num; }> >Obj : ; }>(fields: O) => Obj >{ foo: Num } : { foo: Num; } >foo : Num diff --git a/tests/baselines/reference/recursiveTypeComparison.errors.txt b/tests/baselines/reference/recursiveTypeComparison.errors.txt deleted file mode 100644 index f647763b2e275..0000000000000 --- a/tests/baselines/reference/recursiveTypeComparison.errors.txt +++ /dev/null @@ -1,27 +0,0 @@ -tests/cases/compiler/recursiveTypeComparison.ts(14,5): error TS2322: Type 'Observable<{}>' is not assignable to type 'Property'. - Types of property 'needThisOne' are incompatible. - Type 'Observable<{}>' is not assignable to type 'Observable'. - Type '{}' is not assignable to type 'number'. - - -==== tests/cases/compiler/recursiveTypeComparison.ts (1 errors) ==== - // Before fix this would take an exceeding long time to complete (#1170) - - interface Observable { - // This member can't be of type T, Property, or Observable - needThisOne: Observable; - // Add more to make it slower - expo1: Property; // 0.31 seconds in check - expo2: Property; // 3.11 seconds - expo3: Property; // 82.28 seconds - } - interface Property extends Observable { } - - var p: Observable<{}>; - var stuck: Property = p; - ~~~~~ -!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Property'. -!!! error TS2322: Types of property 'needThisOne' are incompatible. -!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable'. -!!! error TS2322: Type '{}' is not assignable to type 'number'. - \ No newline at end of file diff --git a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt index 21f4bc58cff92..d24b88a7a94cf 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt +++ b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt @@ -17,19 +17,15 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(21,1): error TS2322: Type '(x: tests/cases/compiler/strictFunctionTypesErrors.ts(23,1): error TS2322: Type '(x: string) => Object' is not assignable to type '(x: string) => string'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(33,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(34,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(36,1): error TS2322: Type 'Func' is not assignable to type 'Func'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(37,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(38,1): error TS2322: Type 'Func' is not assignable to type 'Func'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(44,1): error TS2322: Type 'Func' is not assignable to type 'Func'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(46,1): error TS2322: Type 'Func' is not assignable to type 'Func'. @@ -39,39 +35,26 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(57,1): error TS2322: Type 'Fun tests/cases/compiler/strictFunctionTypesErrors.ts(58,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(61,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. - Types of parameters 'x' and 'x' are incompatible. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Func' is not assignable to type 'Func'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(62,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. - Types of parameters 'x' and 'x' are incompatible. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(65,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. - Types of parameters 'x' and 'x' are incompatible. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(66,1): error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. - Types of parameters 'x' and 'x' are incompatible. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(67,1): error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(74,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(75,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(76,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(79,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(80,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. - Types of parameters 'x' and 'x' are incompatible. - Type 'Object' is not assignable to type 'string'. + Type 'Object' is not assignable to type 'string'. tests/cases/compiler/strictFunctionTypesErrors.ts(83,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. Type 'Func' is not assignable to type 'Func'. tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Func>' is not assignable to type 'Func>'. @@ -79,13 +62,9 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Fun tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. Property 'dog' is missing in type 'Animal' but required in type 'Dog'. tests/cases/compiler/strictFunctionTypesErrors.ts(126,1): error TS2322: Type 'Crate' is not assignable to type 'Crate'. - Types of property 'onSetItem' are incompatible. - Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'. - Types of parameters 'item' and 'item' are incompatible. - Type 'Animal' is not assignable to type 'Dog'. + Type 'Animal' is not assignable to type 'Dog'. tests/cases/compiler/strictFunctionTypesErrors.ts(127,1): error TS2322: Type 'Crate' is not assignable to type 'Crate'. - Types of property 'item' are incompatible. - Type 'Animal' is not assignable to type 'Dog'. + Type 'Animal' is not assignable to type 'Dog'. tests/cases/compiler/strictFunctionTypesErrors.ts(133,1): error TS2322: Type '(f: (x: Dog) => Dog) => void' is not assignable to type '(f: (x: Animal) => Animal) => void'. Types of parameters 'f' and 'f' are incompatible. Type 'Animal' is not assignable to type 'Dog'. @@ -164,13 +143,11 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c g1 = g3; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g1 = g4; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g2 = g1; // Error ~~ @@ -179,13 +156,11 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c g2 = g3; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g2 = g4; // Error ~~ !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. g3 = g1; // Ok g3 = g2; // Ok @@ -223,29 +198,22 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c h3 = h1; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, Object>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. h3 = h2; // Error ~~ !!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, Object>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. h3 = h4; // Ok h4 = h1; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. h4 = h2; // Error ~~ !!! error TS2322: Type 'Func, string>' is not assignable to type 'Func, string>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Func' is not assignable to type 'Func'. h4 = h3; // Error ~~ !!! error TS2322: Type 'Func, Object>' is not assignable to type 'Func, string>'. @@ -260,30 +228,24 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. !!! error TS2322: Type 'Func' is not assignable to type 'Func'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. i1 = i3; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i1 = i4; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i2 = i1; // Ok i2 = i3; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i2 = i4; // Error ~~ !!! error TS2322: Type 'Func>' is not assignable to type 'Func>'. -!!! error TS2322: Types of parameters 'x' and 'x' are incompatible. -!!! error TS2322: Type 'Object' is not assignable to type 'string'. +!!! error TS2322: Type 'Object' is not assignable to type 'string'. i3 = i1; // Ok i3 = i2; // Error @@ -342,15 +304,11 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c animalCrate = dogCrate; // Error ~~~~~~~~~~~ !!! error TS2322: Type 'Crate' is not assignable to type 'Crate'. -!!! error TS2322: Types of property 'onSetItem' are incompatible. -!!! error TS2322: Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'. -!!! error TS2322: Types of parameters 'item' and 'item' are incompatible. -!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. dogCrate = animalCrate; // Error ~~~~~~~~ !!! error TS2322: Type 'Crate' is not assignable to type 'Crate'. -!!! error TS2322: Types of property 'item' are incompatible. -!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. // Verify that callback parameters are strictly checked diff --git a/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt b/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt index 5fdeab58610af..ab661b6fee7c8 100644 --- a/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt +++ b/tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt @@ -9,16 +9,13 @@ tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(27,1): error TS2322: Typ Property 'kwah' is missing in type 'Foo' but required in type 'Kwah'. tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(48,1): error TS2322: Type 'X' is not assignable to type 'X | Y | Z'. Type 'X' is not assignable to type 'X'. - Types of property 'xProp' are incompatible. - Type 'Foo' is not assignable to type 'Bar'. + Type 'Foo' is not assignable to type 'Bar'. tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(49,1): error TS2322: Type 'Y' is not assignable to type 'X | Y | Z'. Type 'Y' is not assignable to type 'Y'. - Types of property 'yProp' are incompatible. - Type 'Foo' is not assignable to type 'Baz'. + Type 'Foo' is not assignable to type 'Baz'. tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(50,1): error TS2322: Type 'Z' is not assignable to type 'X | Y | Z'. Type 'Z' is not assignable to type 'Z'. - Types of property 'zProp' are incompatible. - Type 'Foo' is not assignable to type 'Kwah'. + Type 'Foo' is not assignable to type 'Kwah'. ==== tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts (6 errors) ==== @@ -88,17 +85,14 @@ tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(50,1): error TS2322: Typ ~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type 'X' is not assignable to type 'X | Y | Z'. !!! error TS2322: Type 'X' is not assignable to type 'X'. -!!! error TS2322: Types of property 'xProp' are incompatible. -!!! error TS2322: Type 'Foo' is not assignable to type 'Bar'. +!!! error TS2322: Type 'Foo' is not assignable to type 'Bar'. thingOfTypeAliases = y; ~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type 'Y' is not assignable to type 'X | Y | Z'. !!! error TS2322: Type 'Y' is not assignable to type 'Y'. -!!! error TS2322: Types of property 'yProp' are incompatible. -!!! error TS2322: Type 'Foo' is not assignable to type 'Baz'. +!!! error TS2322: Type 'Foo' is not assignable to type 'Baz'. thingOfTypeAliases = z; ~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type 'Z' is not assignable to type 'X | Y | Z'. !!! error TS2322: Type 'Z' is not assignable to type 'Z'. -!!! error TS2322: Types of property 'zProp' are incompatible. -!!! error TS2322: Type 'Foo' is not assignable to type 'Kwah'. \ No newline at end of file +!!! error TS2322: Type 'Foo' is not assignable to type 'Kwah'. \ No newline at end of file From a776fda90bd325e426a673123175042c6e63d419 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 26 Feb 2019 14:01:02 -0800 Subject: [PATCH 04/10] Reduce deep nesting limit just a bit so yargs still builds --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65728d600a524..291a6291573a3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13469,7 +13469,7 @@ namespace ts { // Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons // for 5 or more occurrences or instantiations of the type have been recorded on the given stack. It is possible, // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely - // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least 5 + // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least 4 // levels, but unequal at some level beyond that. function isDeeplyNestedType(type: Type, stack: Type[], depth: number): boolean { // We track all object types that have an associated symbol (representing the origin of the type) @@ -13481,7 +13481,7 @@ namespace ts { const t = stack[i]; if (t.flags & TypeFlags.Object && t.symbol === symbol) { count++; - if (count >= 5) return true; + if (count >= 4) return true; } } } From efc9478167319d88d56a0ab616113377906f36c6 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 26 Feb 2019 14:26:09 -0800 Subject: [PATCH 05/10] Handle circular identities in isNonGeneric --- src/compiler/checker.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 291a6291573a3..74cab4d1c3e25 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12813,6 +12813,12 @@ namespace ts { return Ternary.False; function isNonGeneric(type: Type) { + // If we're already doing identity checking, don't dive into a new `isIdenticalTo` call, so we + // can properly trigger a `Maybe` result (which we interpret as "potentially generic" here) if + // relating the identity of the type ends up being recursive + if (relation === identityRelation) { + return isRelatedTo(getRestrictiveInstantiation(type), type) === Ternary.True; + } return isTypeIdenticalTo(getRestrictiveInstantiation(type), type); } From ec0b6718ddcce37675b5d702e340a546b7a29983 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 26 Feb 2019 16:58:39 -0800 Subject: [PATCH 06/10] Use a simple traversal of the types rather than the restrictive instantiation --- src/compiler/checker.ts | 91 +++++++++- .../reference/callsOnComplexSignatures.types | 16 +- .../baselines/reference/specedNoStackBlown.js | 47 ++++++ .../reference/specedNoStackBlown.symbols | 158 ++++++++++++++++++ .../reference/specedNoStackBlown.types | 64 +++++++ tests/cases/compiler/specedNoStackBlown.ts | 35 ++++ 6 files changed, 397 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/specedNoStackBlown.js create mode 100644 tests/baselines/reference/specedNoStackBlown.symbols create mode 100644 tests/baselines/reference/specedNoStackBlown.types create mode 100644 tests/cases/compiler/specedNoStackBlown.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c7e95848f0d24..a9d8d5129f362 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12824,13 +12824,16 @@ namespace ts { return Ternary.False; function isNonGeneric(type: Type) { - // If we're already doing identity checking, don't dive into a new `isIdenticalTo` call, so we - // can properly trigger a `Maybe` result (which we interpret as "potentially generic" here) if - // relating the identity of the type ends up being recursive - if (relation === identityRelation) { - return isRelatedTo(getRestrictiveInstantiation(type), type) === Ternary.True; + let containsGeneric = false; + traverseType(type, markTypeParameter); + return !containsGeneric; + + function markTypeParameter(type: Type) { + if (type.flags & TypeFlags.TypeParameter) { + containsGeneric = true; + } + return containsGeneric; } - return isTypeIdenticalTo(getRestrictiveInstantiation(type), type); } function relateVariances(sourceTypeArguments: ReadonlyArray | undefined, targetTypeArguments: ReadonlyArray | undefined, variances: Variance[]) { @@ -12867,6 +12870,82 @@ namespace ts { } } + function traverseType(type: Type, visitor: (t: Type) => boolean) { + const visited = createMap(); + return visitType(type); + + function visitType(type: Type) { + const id = "" + getTypeId(type); + if (visited.has(id)) return; + visited.set(id, true); + if (visitor(type)) return; + const flags = type.flags; + if (flags & TypeFlags.Object) { + const objectFlags = (type).objectFlags; + if (isGenericMappedType(type)) { + visitType(getConstraintTypeFromMappedType(type)); + visitType(getTemplateTypeFromMappedType(type)); + } + else if (objectFlags & ObjectFlags.ReverseMapped) { + visitType((type as ReverseMappedType).mappedType); + visitType((type as ReverseMappedType).source); + visitType((type as ReverseMappedType).constraintType); + } + else if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped | ObjectFlags.ClassOrInterface)) { + resolveStructuredTypeMembers(type as StructuredType); + const strIdx = getIndexInfoOfType(type, IndexKind.String); + if (strIdx) { + visitType(strIdx.type); + } + const numIdx = getIndexInfoOfType(type, IndexKind.Number); + if (numIdx) { + visitType(numIdx.type); + } + for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Call)) { + visitSignature(sig); + } + for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Construct)) { + visitSignature(sig); + } + for (const member of ((type as ResolvedType).properties || emptyArray)) { + visitType(getTypeOfSymbol(member)); + } + } + else if (objectFlags & ObjectFlags.Reference) { + const typeArguments = (type).typeArguments; + forEach(typeArguments, visitType); + } + } + else if (flags & TypeFlags.UnionOrIntersection) { + forEachType(type, visitType); + } + else if (flags & TypeFlags.Index) { + visitType((type as IndexType).type); + } + else if (flags & TypeFlags.IndexedAccess) { + visitType((type as IndexedAccessType).objectType); + visitType((type as IndexedAccessType).indexType); + } + else if (flags & TypeFlags.Conditional) { + visitType((type as ConditionalType).checkType); + visitType((type as ConditionalType).extendsType); + visitType(getTrueTypeFromConditionalType(type as ConditionalType)); + visitType(getFalseTypeFromConditionalType(type as ConditionalType)); + } + else if (flags & TypeFlags.Substitution) { + visitType((type as SubstitutionType).typeVariable); + visitType((type as SubstitutionType).substitute); + } + } + + function visitSignature(sig: Signature) { + for (const param of sig.parameters) { + visitType(getTypeOfSymbol(param)); + } + visitType(getReturnTypeOfSignature(sig)); + } + } + // A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. diff --git a/tests/baselines/reference/callsOnComplexSignatures.types b/tests/baselines/reference/callsOnComplexSignatures.types index 4eb90ac43e345..fff661c9450b0 100644 --- a/tests/baselines/reference/callsOnComplexSignatures.types +++ b/tests/baselines/reference/callsOnComplexSignatures.types @@ -358,22 +358,22 @@ function test5() { // Union of all intrinsics and components of `any` function App(props: { component:React.ReactType }) { ->App : (props: { component: React.ReactType; }) => JSX.Element ->props : { component: React.ReactType; } ->component : React.ReactType +>App : (props: { component: string | React.ComponentClass | React.StatelessComponent; }) => JSX.Element +>props : { component: string | React.ComponentClass | React.StatelessComponent; } +>component : string | React.ComponentClass | React.StatelessComponent >React : any const Comp: React.ReactType = props.component; ->Comp : React.ReactType +>Comp : string | React.ComponentClass | React.StatelessComponent >React : any ->props.component : React.ReactType ->props : { component: React.ReactType; } ->component : React.ReactType +>props.component : string | React.ComponentClass | React.StatelessComponent +>props : { component: string | React.ComponentClass | React.StatelessComponent; } +>component : string | React.ComponentClass | React.StatelessComponent return (); >() : JSX.Element > : JSX.Element ->Comp : React.ReactType +>Comp : string | React.ComponentClass | React.StatelessComponent } // custom components with non-subset props diff --git a/tests/baselines/reference/specedNoStackBlown.js b/tests/baselines/reference/specedNoStackBlown.js new file mode 100644 index 0000000000000..034caf4d7eba8 --- /dev/null +++ b/tests/baselines/reference/specedNoStackBlown.js @@ -0,0 +1,47 @@ +//// [specedNoStackBlown.ts] +// Type definitions for spected 0.7 +// Project: https://github.com/25th-floor/spected +// Definitions by: Benjamin Makus +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +declare function spected = SpecValue>(spec: SPEC, input: ROOTINPUT): Result; + +type Predicate = (value: INPUT, inputs: ROOTINPUT) => boolean; + +type ErrorMsg = + | (string | number | boolean | symbol | null | undefined | object) + | ((value: INPUT, field: string) => any); + +export type Spec = [Predicate, ErrorMsg]; + +export type SpecArray = Array>; + +export type SpecFunction = [INPUT] extends [ReadonlyArray] + ? (value: INPUT) => ReadonlyArray> + : [INPUT] extends [object] + ? (value: INPUT) => SpecObject + : (value: INPUT) => SpecArray; + +export type SpecObject = Partial<{[key in keyof INPUT]: SpecValue}>; + +export type SpecValue = [INPUT] extends [ReadonlyArray] + ? SpecArray | SpecFunction + : [INPUT] extends [object] + ? SpecArray | SpecFunction | SpecObject + : SpecArray | SpecFunction; + +export type Result = {[key in keyof INPUT]: true | any[] | Result}; + +export default spected; + + +//// [specedNoStackBlown.js] +"use strict"; +// Type definitions for spected 0.7 +// Project: https://github.com/25th-floor/spected +// Definitions by: Benjamin Makus +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 +exports.__esModule = true; +exports["default"] = spected; diff --git a/tests/baselines/reference/specedNoStackBlown.symbols b/tests/baselines/reference/specedNoStackBlown.symbols new file mode 100644 index 0000000000000..299e31e98082c --- /dev/null +++ b/tests/baselines/reference/specedNoStackBlown.symbols @@ -0,0 +1,158 @@ +=== tests/cases/compiler/specedNoStackBlown.ts === +// Type definitions for spected 0.7 +// Project: https://github.com/25th-floor/spected +// Definitions by: Benjamin Makus +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +declare function spected = SpecValue>(spec: SPEC, input: ROOTINPUT): Result; +>spected : Symbol(spected, Decl(specedNoStackBlown.ts, 0, 0)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 6, 35)) +>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>spec : Symbol(spec, Decl(specedNoStackBlown.ts, 6, 116)) +>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 6, 35)) +>input : Symbol(input, Decl(specedNoStackBlown.ts, 6, 127)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>Result : Symbol(Result, Decl(specedNoStackBlown.ts, 30, 75)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 6, 25)) +>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 6, 35)) + +type Predicate = (value: INPUT, inputs: ROOTINPUT) => boolean; +>Predicate : Symbol(Predicate, Decl(specedNoStackBlown.ts, 6, 171)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 8, 15)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 8, 21)) +>value : Symbol(value, Decl(specedNoStackBlown.ts, 8, 36)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 8, 15)) +>inputs : Symbol(inputs, Decl(specedNoStackBlown.ts, 8, 49)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 8, 21)) + +type ErrorMsg = +>ErrorMsg : Symbol(ErrorMsg, Decl(specedNoStackBlown.ts, 8, 80)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 10, 14)) + + | (string | number | boolean | symbol | null | undefined | object) + | ((value: INPUT, field: string) => any); +>value : Symbol(value, Decl(specedNoStackBlown.ts, 12, 8)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 10, 14)) +>field : Symbol(field, Decl(specedNoStackBlown.ts, 12, 21)) + +export type Spec = [Predicate, ErrorMsg]; +>Spec : Symbol(Spec, Decl(specedNoStackBlown.ts, 12, 45)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 14, 17)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 14, 23)) +>Predicate : Symbol(Predicate, Decl(specedNoStackBlown.ts, 6, 171)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 14, 17)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 14, 23)) +>ErrorMsg : Symbol(ErrorMsg, Decl(specedNoStackBlown.ts, 8, 80)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 14, 17)) + +export type SpecArray = Array>; +>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 16, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 16, 28)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Spec : Symbol(Spec, Decl(specedNoStackBlown.ts, 12, 45)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 16, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 16, 28)) + +export type SpecFunction = [INPUT] extends [ReadonlyArray] +>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>U : Symbol(U, Decl(specedNoStackBlown.ts, 18, 87)) + + ? (value: INPUT) => ReadonlyArray> +>value : Symbol(value, Decl(specedNoStackBlown.ts, 19, 7)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) +>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90)) +>U : Symbol(U, Decl(specedNoStackBlown.ts, 18, 87)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31)) + + : [INPUT] extends [object] +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) + + ? (value: INPUT) => SpecObject +>value : Symbol(value, Decl(specedNoStackBlown.ts, 21, 11)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>SpecObject : Symbol(SpecObject, Decl(specedNoStackBlown.ts, 22, 56)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31)) + + : (value: INPUT) => SpecArray; +>value : Symbol(value, Decl(specedNoStackBlown.ts, 22, 11)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 18, 25)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 18, 31)) + +export type SpecObject = Partial<{[key in keyof INPUT]: SpecValue}>; +>SpecObject : Symbol(SpecObject, Decl(specedNoStackBlown.ts, 22, 56)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 24, 23)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 24, 29)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>key : Symbol(key, Decl(specedNoStackBlown.ts, 24, 59)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 24, 23)) +>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 24, 23)) +>key : Symbol(key, Decl(specedNoStackBlown.ts, 24, 59)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 24, 29)) + +export type SpecValue = [INPUT] extends [ReadonlyArray] +>SpecValue : Symbol(SpecValue, Decl(specedNoStackBlown.ts, 24, 115)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --)) + + ? SpecArray | SpecFunction +>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) +>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) + + : [INPUT] extends [object] +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) + + ? SpecArray | SpecFunction | SpecObject +>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) +>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) +>SpecObject : Symbol(SpecObject, Decl(specedNoStackBlown.ts, 22, 56)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) + + : SpecArray | SpecFunction; +>SpecArray : Symbol(SpecArray, Decl(specedNoStackBlown.ts, 14, 90)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) +>SpecFunction : Symbol(SpecFunction, Decl(specedNoStackBlown.ts, 16, 78)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 26, 22)) +>ROOTINPUT : Symbol(ROOTINPUT, Decl(specedNoStackBlown.ts, 26, 28)) + +export type Result = {[key in keyof INPUT]: true | any[] | Result}; +>Result : Symbol(Result, Decl(specedNoStackBlown.ts, 30, 75)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 32, 19)) +>SPEC : Symbol(SPEC, Decl(specedNoStackBlown.ts, 32, 25)) +>key : Symbol(key, Decl(specedNoStackBlown.ts, 32, 36)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 32, 19)) +>Result : Symbol(Result, Decl(specedNoStackBlown.ts, 30, 75)) +>INPUT : Symbol(INPUT, Decl(specedNoStackBlown.ts, 32, 19)) +>key : Symbol(key, Decl(specedNoStackBlown.ts, 32, 36)) + +export default spected; +>spected : Symbol(spected, Decl(specedNoStackBlown.ts, 0, 0)) + diff --git a/tests/baselines/reference/specedNoStackBlown.types b/tests/baselines/reference/specedNoStackBlown.types new file mode 100644 index 0000000000000..654f98941df1a --- /dev/null +++ b/tests/baselines/reference/specedNoStackBlown.types @@ -0,0 +1,64 @@ +=== tests/cases/compiler/specedNoStackBlown.ts === +// Type definitions for spected 0.7 +// Project: https://github.com/25th-floor/spected +// Definitions by: Benjamin Makus +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +declare function spected = SpecValue>(spec: SPEC, input: ROOTINPUT): Result; +>spected : = SpecValue>(spec: SPEC, input: ROOTINPUT) => Result +>spec : SPEC +>input : ROOTINPUT + +type Predicate = (value: INPUT, inputs: ROOTINPUT) => boolean; +>Predicate : Predicate +>value : INPUT +>inputs : ROOTINPUT + +type ErrorMsg = +>ErrorMsg : ErrorMsg + + | (string | number | boolean | symbol | null | undefined | object) +>null : null + + | ((value: INPUT, field: string) => any); +>value : INPUT +>field : string + +export type Spec = [Predicate, ErrorMsg]; +>Spec : [Predicate, ErrorMsg] + +export type SpecArray = Array>; +>SpecArray : [Predicate, ErrorMsg][] + +export type SpecFunction = [INPUT] extends [ReadonlyArray] +>SpecFunction : SpecFunction + + ? (value: INPUT) => ReadonlyArray> +>value : INPUT + + : [INPUT] extends [object] + ? (value: INPUT) => SpecObject +>value : INPUT + + : (value: INPUT) => SpecArray; +>value : INPUT + +export type SpecObject = Partial<{[key in keyof INPUT]: SpecValue}>; +>SpecObject : Partial<{ [key in keyof INPUT]: SpecValue; }> + +export type SpecValue = [INPUT] extends [ReadonlyArray] +>SpecValue : SpecValue + + ? SpecArray | SpecFunction + : [INPUT] extends [object] + ? SpecArray | SpecFunction | SpecObject + : SpecArray | SpecFunction; + +export type Result = {[key in keyof INPUT]: true | any[] | Result}; +>Result : Result +>true : true + +export default spected; +>spected : = SpecValue>(spec: SPEC, input: ROOTINPUT) => Result + diff --git a/tests/cases/compiler/specedNoStackBlown.ts b/tests/cases/compiler/specedNoStackBlown.ts new file mode 100644 index 0000000000000..9ada3ce1c55a9 --- /dev/null +++ b/tests/cases/compiler/specedNoStackBlown.ts @@ -0,0 +1,35 @@ +// Type definitions for spected 0.7 +// Project: https://github.com/25th-floor/spected +// Definitions by: Benjamin Makus +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.8 + +declare function spected = SpecValue>(spec: SPEC, input: ROOTINPUT): Result; + +type Predicate = (value: INPUT, inputs: ROOTINPUT) => boolean; + +type ErrorMsg = + | (string | number | boolean | symbol | null | undefined | object) + | ((value: INPUT, field: string) => any); + +export type Spec = [Predicate, ErrorMsg]; + +export type SpecArray = Array>; + +export type SpecFunction = [INPUT] extends [ReadonlyArray] + ? (value: INPUT) => ReadonlyArray> + : [INPUT] extends [object] + ? (value: INPUT) => SpecObject + : (value: INPUT) => SpecArray; + +export type SpecObject = Partial<{[key in keyof INPUT]: SpecValue}>; + +export type SpecValue = [INPUT] extends [ReadonlyArray] + ? SpecArray | SpecFunction + : [INPUT] extends [object] + ? SpecArray | SpecFunction | SpecObject + : SpecArray | SpecFunction; + +export type Result = {[key in keyof INPUT]: true | any[] | Result}; + +export default spected; From 6df1629204739f19b60d2c9c3df431bc7cfdc094 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 26 Feb 2019 17:49:55 -0800 Subject: [PATCH 07/10] Cache the bits using an existing field to further reduce any time nongeneric check takes --- src/compiler/checker.ts | 124 +++++++++++++++++++++++----------------- src/compiler/types.ts | 9 ++- 2 files changed, 80 insertions(+), 53 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a9d8d5129f362..77cdc86890b1b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2786,6 +2786,7 @@ namespace ts { function createTypeParameter(symbol?: Symbol) { const type = createType(TypeFlags.TypeParameter); if (symbol) type.symbol = symbol; + type.calculatedFlags = CalculatedTypeFlags.HasCalculatedContainsTypeParameter | CalculatedTypeFlags.ContainsTypeParameter; return type; } @@ -12609,7 +12610,7 @@ namespace ts { // the order in which things were checked. if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && - !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { + !(source.calculatedFlags! & CalculatedTypeFlags.IsMarkerType || target.calculatedFlags! & CalculatedTypeFlags.IsMarkerType)) { const variances = getAliasVariances(source.aliasSymbol); const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances); if (varianceResult !== undefined) { @@ -12824,16 +12825,7 @@ namespace ts { return Ternary.False; function isNonGeneric(type: Type) { - let containsGeneric = false; - traverseType(type, markTypeParameter); - return !containsGeneric; - - function markTypeParameter(type: Type) { - if (type.flags & TypeFlags.TypeParameter) { - containsGeneric = true; - } - return containsGeneric; - } + return !hasAggregatedCalculatedFlag(type, CalculatedTypeFlags.ContainsTypeParameter); } function relateVariances(sourceTypeArguments: ReadonlyArray | undefined, targetTypeArguments: ReadonlyArray | undefined, variances: Variance[]) { @@ -12870,79 +12862,107 @@ namespace ts { } } - function traverseType(type: Type, visitor: (t: Type) => boolean) { + function hasAggregatedCalculatedFlag(type: Type, storageBit: CalculatedTypeFlags) { + const checkedBit = storageBit >> 1; const visited = createMap(); return visitType(type); - function visitType(type: Type) { + function visitType(type: Type): boolean { const id = "" + getTypeId(type); - if (visited.has(id)) return; + if (visited.has(id)) return false; visited.set(id, true); - if (visitor(type)) return; const flags = type.flags; + if (type.calculatedFlags! & checkedBit) { + return !!(type.calculatedFlags! & storageBit); + } if (flags & TypeFlags.Object) { const objectFlags = (type).objectFlags; if (isGenericMappedType(type)) { - visitType(getConstraintTypeFromMappedType(type)); - visitType(getTemplateTypeFromMappedType(type)); + return cacheResult(type, visitType(getConstraintTypeFromMappedType(type)) || visitType(getTemplateTypeFromMappedType(type))); } else if (objectFlags & ObjectFlags.ReverseMapped) { - visitType((type as ReverseMappedType).mappedType); - visitType((type as ReverseMappedType).source); - visitType((type as ReverseMappedType).constraintType); + return cacheResult(type, visitType((type as ReverseMappedType).mappedType) || + visitType((type as ReverseMappedType).source) || + visitType((type as ReverseMappedType).constraintType)); } else if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped | ObjectFlags.ClassOrInterface)) { - resolveStructuredTypeMembers(type as StructuredType); - const strIdx = getIndexInfoOfType(type, IndexKind.String); - if (strIdx) { - visitType(strIdx.type); - } - const numIdx = getIndexInfoOfType(type, IndexKind.Number); - if (numIdx) { - visitType(numIdx.type); - } - for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Call)) { - visitSignature(sig); - } - for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Construct)) { - visitSignature(sig); - } - for (const member of ((type as ResolvedType).properties || emptyArray)) { - visitType(getTypeOfSymbol(member)); - } + return cacheResult(type, visitStructuredType(type as StructuredType)); } else if (objectFlags & ObjectFlags.Reference) { const typeArguments = (type).typeArguments; - forEach(typeArguments, visitType); + return cacheResult(type, some(typeArguments, visitType)); } } else if (flags & TypeFlags.UnionOrIntersection) { - forEachType(type, visitType); + return cacheResult(type, some((type as UnionOrIntersectionType).types, visitType)); } else if (flags & TypeFlags.Index) { - visitType((type as IndexType).type); + return cacheResult(type, visitType((type as IndexType).type)); } else if (flags & TypeFlags.IndexedAccess) { - visitType((type as IndexedAccessType).objectType); - visitType((type as IndexedAccessType).indexType); + return cacheResult(type, visitType((type as IndexedAccessType).objectType) || + visitType((type as IndexedAccessType).indexType)); } else if (flags & TypeFlags.Conditional) { - visitType((type as ConditionalType).checkType); - visitType((type as ConditionalType).extendsType); - visitType(getTrueTypeFromConditionalType(type as ConditionalType)); - visitType(getFalseTypeFromConditionalType(type as ConditionalType)); + return cacheResult(type, visitType((type as ConditionalType).checkType) || + visitType((type as ConditionalType).extendsType) || + visitType(getTrueTypeFromConditionalType(type as ConditionalType)) || + visitType(getFalseTypeFromConditionalType(type as ConditionalType))); } else if (flags & TypeFlags.Substitution) { - visitType((type as SubstitutionType).typeVariable); - visitType((type as SubstitutionType).substitute); + return cacheResult(type, visitType((type as SubstitutionType).typeVariable) || + visitType((type as SubstitutionType).substitute)); + } + return false; + } + + function cacheResult(type: Type, result: boolean) { + type.calculatedFlags! |= checkedBit; + if (result) { + type.calculatedFlags! |= storageBit; + } + return result; + } + + function visitStructuredType(type: StructuredType) { + resolveStructuredTypeMembers(type); + const strIdx = getIndexInfoOfType(type, IndexKind.String); + if (strIdx) { + if (visitType(strIdx.type)) { + return true; + } + } + const numIdx = getIndexInfoOfType(type, IndexKind.Number); + if (numIdx) { + if (visitType(numIdx.type)) { + return true; + } } + for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Call)) { + if (visitSignature(sig)) { + return true; + } + } + for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Construct)) { + if (visitSignature(sig)) { + return true; + } + } + for (const member of ((type as ResolvedType).properties || emptyArray)) { + if (visitType(getTypeOfSymbol(member))) { + return true; + } + } + return false; } function visitSignature(sig: Signature) { for (const param of sig.parameters) { - visitType(getTypeOfSymbol(param)); + if (visitType(getTypeOfSymbol(param))) { + return true; + } } - visitType(getReturnTypeOfSignature(sig)); + return visitType(getReturnTypeOfSignature(sig)); } } @@ -13411,7 +13431,7 @@ namespace ts { const links = getSymbolLinks(symbol); return getVariancesWorker(links.typeParameters, links, (_links, param, marker) => { const type = getTypeAliasInstantiation(symbol, instantiateTypes(links.typeParameters!, makeUnaryTypeMapper(param, marker))); - type.aliasTypeArgumentsContainsMarker = true; + type.calculatedFlags! |= CalculatedTypeFlags.IsMarkerType; return type; }); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cce869df44ea1..a410fac859e9c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3919,7 +3919,7 @@ namespace ts { pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any) aliasSymbol?: Symbol; // Alias associated with type aliasTypeArguments?: ReadonlyArray; // Alias type arguments (if any) - /* @internal */ aliasTypeArgumentsContainsMarker?: boolean; // Alias type arguments (if any) + /* @internal */ calculatedFlags?: CalculatedTypeFlags; /* @internal */ permissiveInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type /* @internal */ @@ -3928,6 +3928,13 @@ namespace ts { immediateBaseConstraint?: Type; // Immediate base constraint cache } + /* @internal */ + export const enum CalculatedTypeFlags { + IsMarkerType = 1 << 0, + HasCalculatedContainsTypeParameter = 1 << 1, + ContainsTypeParameter = 1 << 2, + } + /* @internal */ // Intrinsic types (TypeFlags.Intrinsic) export interface IntrinsicType extends Type { From 1565c97a026bb196c3079d2662cac68d7f606049 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 26 Feb 2019 18:18:09 -0800 Subject: [PATCH 08/10] Revert to using an existing mapper, use permissive > restrictive --- src/compiler/checker.ts | 117 ++---------------- src/compiler/types.ts | 9 +- .../reference/callsOnComplexSignatures.types | 16 +-- 3 files changed, 18 insertions(+), 124 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 77cdc86890b1b..48e3620d3fb98 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2786,7 +2786,6 @@ namespace ts { function createTypeParameter(symbol?: Symbol) { const type = createType(TypeFlags.TypeParameter); if (symbol) type.symbol = symbol; - type.calculatedFlags = CalculatedTypeFlags.HasCalculatedContainsTypeParameter | CalculatedTypeFlags.ContainsTypeParameter; return type; } @@ -12610,7 +12609,7 @@ namespace ts { // the order in which things were checked. if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && - !(source.calculatedFlags! & CalculatedTypeFlags.IsMarkerType || target.calculatedFlags! & CalculatedTypeFlags.IsMarkerType)) { + !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { const variances = getAliasVariances(source.aliasSymbol); const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances); if (varianceResult !== undefined) { @@ -12825,7 +12824,13 @@ namespace ts { return Ternary.False; function isNonGeneric(type: Type) { - return !hasAggregatedCalculatedFlag(type, CalculatedTypeFlags.ContainsTypeParameter); + // If we're already in identity relationship checking, we should use `isRelatedTo` + // to catch the `Maybe` from an excessively deep type (which we then assume means + // that the type could possibly contain a generic) + if (relation === identityRelation) { + return isRelatedTo(type, getPermissiveInstantiation(type)) === Ternary.True; + } + return isTypeIdenticalTo(type, getPermissiveInstantiation(type)); } function relateVariances(sourceTypeArguments: ReadonlyArray | undefined, targetTypeArguments: ReadonlyArray | undefined, variances: Variance[]) { @@ -12862,110 +12867,6 @@ namespace ts { } } - function hasAggregatedCalculatedFlag(type: Type, storageBit: CalculatedTypeFlags) { - const checkedBit = storageBit >> 1; - const visited = createMap(); - return visitType(type); - - function visitType(type: Type): boolean { - const id = "" + getTypeId(type); - if (visited.has(id)) return false; - visited.set(id, true); - const flags = type.flags; - if (type.calculatedFlags! & checkedBit) { - return !!(type.calculatedFlags! & storageBit); - } - if (flags & TypeFlags.Object) { - const objectFlags = (type).objectFlags; - if (isGenericMappedType(type)) { - return cacheResult(type, visitType(getConstraintTypeFromMappedType(type)) || visitType(getTemplateTypeFromMappedType(type))); - } - else if (objectFlags & ObjectFlags.ReverseMapped) { - return cacheResult(type, visitType((type as ReverseMappedType).mappedType) || - visitType((type as ReverseMappedType).source) || - visitType((type as ReverseMappedType).constraintType)); - } - else if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped | ObjectFlags.ClassOrInterface)) { - return cacheResult(type, visitStructuredType(type as StructuredType)); - } - else if (objectFlags & ObjectFlags.Reference) { - const typeArguments = (type).typeArguments; - return cacheResult(type, some(typeArguments, visitType)); - } - } - else if (flags & TypeFlags.UnionOrIntersection) { - return cacheResult(type, some((type as UnionOrIntersectionType).types, visitType)); - } - else if (flags & TypeFlags.Index) { - return cacheResult(type, visitType((type as IndexType).type)); - } - else if (flags & TypeFlags.IndexedAccess) { - return cacheResult(type, visitType((type as IndexedAccessType).objectType) || - visitType((type as IndexedAccessType).indexType)); - } - else if (flags & TypeFlags.Conditional) { - return cacheResult(type, visitType((type as ConditionalType).checkType) || - visitType((type as ConditionalType).extendsType) || - visitType(getTrueTypeFromConditionalType(type as ConditionalType)) || - visitType(getFalseTypeFromConditionalType(type as ConditionalType))); - } - else if (flags & TypeFlags.Substitution) { - return cacheResult(type, visitType((type as SubstitutionType).typeVariable) || - visitType((type as SubstitutionType).substitute)); - } - return false; - } - - function cacheResult(type: Type, result: boolean) { - type.calculatedFlags! |= checkedBit; - if (result) { - type.calculatedFlags! |= storageBit; - } - return result; - } - - function visitStructuredType(type: StructuredType) { - resolveStructuredTypeMembers(type); - const strIdx = getIndexInfoOfType(type, IndexKind.String); - if (strIdx) { - if (visitType(strIdx.type)) { - return true; - } - } - const numIdx = getIndexInfoOfType(type, IndexKind.Number); - if (numIdx) { - if (visitType(numIdx.type)) { - return true; - } - } - for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Call)) { - if (visitSignature(sig)) { - return true; - } - } - for (const sig of getSignaturesOfStructuredType(type, SignatureKind.Construct)) { - if (visitSignature(sig)) { - return true; - } - } - for (const member of ((type as ResolvedType).properties || emptyArray)) { - if (visitType(getTypeOfSymbol(member))) { - return true; - } - } - return false; - } - - function visitSignature(sig: Signature) { - for (const param of sig.parameters) { - if (visitType(getTypeOfSymbol(param))) { - return true; - } - } - return visitType(getReturnTypeOfSignature(sig)); - } - } - // A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. @@ -13431,7 +13332,7 @@ namespace ts { const links = getSymbolLinks(symbol); return getVariancesWorker(links.typeParameters, links, (_links, param, marker) => { const type = getTypeAliasInstantiation(symbol, instantiateTypes(links.typeParameters!, makeUnaryTypeMapper(param, marker))); - type.calculatedFlags! |= CalculatedTypeFlags.IsMarkerType; + type.aliasTypeArgumentsContainsMarker = true; return type; }); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a410fac859e9c..cce869df44ea1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3919,7 +3919,7 @@ namespace ts { pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any) aliasSymbol?: Symbol; // Alias associated with type aliasTypeArguments?: ReadonlyArray; // Alias type arguments (if any) - /* @internal */ calculatedFlags?: CalculatedTypeFlags; + /* @internal */ aliasTypeArgumentsContainsMarker?: boolean; // Alias type arguments (if any) /* @internal */ permissiveInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type /* @internal */ @@ -3928,13 +3928,6 @@ namespace ts { immediateBaseConstraint?: Type; // Immediate base constraint cache } - /* @internal */ - export const enum CalculatedTypeFlags { - IsMarkerType = 1 << 0, - HasCalculatedContainsTypeParameter = 1 << 1, - ContainsTypeParameter = 1 << 2, - } - /* @internal */ // Intrinsic types (TypeFlags.Intrinsic) export interface IntrinsicType extends Type { diff --git a/tests/baselines/reference/callsOnComplexSignatures.types b/tests/baselines/reference/callsOnComplexSignatures.types index fff661c9450b0..4eb90ac43e345 100644 --- a/tests/baselines/reference/callsOnComplexSignatures.types +++ b/tests/baselines/reference/callsOnComplexSignatures.types @@ -358,22 +358,22 @@ function test5() { // Union of all intrinsics and components of `any` function App(props: { component:React.ReactType }) { ->App : (props: { component: string | React.ComponentClass | React.StatelessComponent; }) => JSX.Element ->props : { component: string | React.ComponentClass | React.StatelessComponent; } ->component : string | React.ComponentClass | React.StatelessComponent +>App : (props: { component: React.ReactType; }) => JSX.Element +>props : { component: React.ReactType; } +>component : React.ReactType >React : any const Comp: React.ReactType = props.component; ->Comp : string | React.ComponentClass | React.StatelessComponent +>Comp : React.ReactType >React : any ->props.component : string | React.ComponentClass | React.StatelessComponent ->props : { component: string | React.ComponentClass | React.StatelessComponent; } ->component : string | React.ComponentClass | React.StatelessComponent +>props.component : React.ReactType +>props : { component: React.ReactType; } +>component : React.ReactType return (); >() : JSX.Element > : JSX.Element ->Comp : string | React.ComponentClass | React.StatelessComponent +>Comp : React.ReactType } // custom components with non-subset props From 0fe6d9b4edede93d1c95f0e0852f2dffe8018800 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 27 Feb 2019 13:41:45 -0800 Subject: [PATCH 09/10] Revert constant change --- 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 289db32775830..b8bd6f048f1a1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13497,7 +13497,7 @@ namespace ts { const t = stack[i]; if (t.flags & TypeFlags.Object && t.symbol === symbol) { count++; - if (count >= 4) return true; + if (count >= 5) return true; } } } From f8989af2d0929b023b595f1175d186d3d8c4bae9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 27 Feb 2019 13:44:30 -0800 Subject: [PATCH 10/10] And revert the comment, too --- 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 b8bd6f048f1a1..247c789577c1a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13485,7 +13485,7 @@ namespace ts { // Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons // for 5 or more occurrences or instantiations of the type have been recorded on the given stack. It is possible, // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely - // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least 4 + // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least 5 // levels, but unequal at some level beyond that. function isDeeplyNestedType(type: Type, stack: Type[], depth: number): boolean { // We track all object types that have an associated symbol (representing the origin of the type)