From d093d6a1f8311cf080f84065c333d02bc71bd71e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 2 Apr 2018 09:22:46 -0700 Subject: [PATCH 1/3] Less aggressive test for type parameter references in conditional types --- src/compiler/checker.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ad82cace11c..2ac1d06d797 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8430,15 +8430,19 @@ namespace ts { return result; } - function getTopConditionalType(node: Node): ConditionalTypeNode { - let result: ConditionalTypeNode; + function isPossiblyReferencedInConditionalType(tp: TypeParameter, node: Node) { + if (isTypeParameterPossiblyReferenced(tp, node)) { + return true; + } while (node) { if (node.kind === SyntaxKind.ConditionalType) { - result = node; + if (isTypeParameterPossiblyReferenced(tp, (node).extendsType)) { + return true; + } } node = node.parent; } - return result; + return false; } function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { @@ -8447,8 +8451,7 @@ namespace ts { const checkType = getTypeFromTypeNode(node.checkType); const aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node); const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true); - const topNode = getTopConditionalType(node); - const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, topNode)); + const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isPossiblyReferencedInConditionalType(tp, node)); const root: ConditionalRoot = { node, checkType, From ec02ccd575afb57c69d8db708889c5d27209d8e1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 2 Apr 2018 09:23:00 -0700 Subject: [PATCH 2/3] Add regression test --- .../types/conditional/conditionalTypes2.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cases/conformance/types/conditional/conditionalTypes2.ts b/tests/cases/conformance/types/conditional/conditionalTypes2.ts index c3418cf924d..4002ab6a0a7 100644 --- a/tests/cases/conformance/types/conditional/conditionalTypes2.ts +++ b/tests/cases/conformance/types/conditional/conditionalTypes2.ts @@ -121,3 +121,18 @@ function foo(value: T) { toString2(value); } } + +// Repro from #23052 + +type A = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } + : T extends V ? T : never; + +type B = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } + : T extends V ? T : never; + +type C = + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; From c2f96a3c7de14135f3d2440cb689a98aae672cbd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 2 Apr 2018 09:23:16 -0700 Subject: [PATCH 3/3] Accept new baselines --- .../reference/conditionalTypes2.errors.txt | 15 ++++ .../baselines/reference/conditionalTypes2.js | 30 +++++++ .../reference/conditionalTypes2.symbols | 82 +++++++++++++++++++ .../reference/conditionalTypes2.types | 82 +++++++++++++++++++ 4 files changed, 209 insertions(+) diff --git a/tests/baselines/reference/conditionalTypes2.errors.txt b/tests/baselines/reference/conditionalTypes2.errors.txt index 7e12ca8523b..0e7844babc6 100644 --- a/tests/baselines/reference/conditionalTypes2.errors.txt +++ b/tests/baselines/reference/conditionalTypes2.errors.txt @@ -176,4 +176,19 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2 toString2(value); } } + + // Repro from #23052 + + type A = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } + : T extends V ? T : never; + + type B = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } + : T extends V ? T : never; + + type C = + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes2.js b/tests/baselines/reference/conditionalTypes2.js index ee2c1fe27fb..7afb39d42bb 100644 --- a/tests/baselines/reference/conditionalTypes2.js +++ b/tests/baselines/reference/conditionalTypes2.js @@ -119,6 +119,21 @@ function foo(value: T) { toString2(value); } } + +// Repro from #23052 + +type A = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } + : T extends V ? T : never; + +type B = + T extends object + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } + : T extends V ? T : never; + +type C = + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; //// [conditionalTypes2.js] @@ -254,3 +269,18 @@ interface B1 extends A1 { declare function toString1(value: object | Function): string; declare function toString2(value: Function): string; declare function foo(value: T): void; +declare type A = T extends object ? { + [Q in { + [P in keyof T]: T[P] extends V ? P : P; + }[keyof T]]: A; +} : T extends V ? T : never; +declare type B = T extends object ? { + [Q in { + [P in keyof T]: T[P] extends V ? P : P; + }[keyof T]]: B; +} : T extends V ? T : never; +declare type C = { + [Q in { + [P in keyof T]: T[P] extends V ? P : P; + }[keyof T]]: C; +}; diff --git a/tests/baselines/reference/conditionalTypes2.symbols b/tests/baselines/reference/conditionalTypes2.symbols index ef58dc6229c..00509458253 100644 --- a/tests/baselines/reference/conditionalTypes2.symbols +++ b/tests/baselines/reference/conditionalTypes2.symbols @@ -414,3 +414,85 @@ function foo(value: T) { } } +// Repro from #23052 + +type A = +>A : Symbol(A, Decl(conditionalTypes2.ts, 119, 1)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 123, 12)) + + T extends object +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 125, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 125, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>A : Symbol(A, Decl(conditionalTypes2.ts, 119, 1)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 125, 9)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 123, 12)) + + : T extends V ? T : never; +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 123, 9)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 123, 7)) + +type B = +>B : Symbol(B, Decl(conditionalTypes2.ts, 126, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) + + T extends object +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 130, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 130, 17)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>B : Symbol(B, Decl(conditionalTypes2.ts, 126, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 130, 9)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) + + : T extends V ? T : never; +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 128, 9)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 128, 7)) + +type C = +>C : Symbol(C, Decl(conditionalTypes2.ts, 131, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 133, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 133, 12)) + + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 134, 5)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 133, 9)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>P : Symbol(P, Decl(conditionalTypes2.ts, 134, 13)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>C : Symbol(C, Decl(conditionalTypes2.ts, 131, 30)) +>T : Symbol(T, Decl(conditionalTypes2.ts, 133, 7)) +>Q : Symbol(Q, Decl(conditionalTypes2.ts, 134, 5)) +>V : Symbol(V, Decl(conditionalTypes2.ts, 133, 9)) +>E : Symbol(E, Decl(conditionalTypes2.ts, 133, 12)) + diff --git a/tests/baselines/reference/conditionalTypes2.types b/tests/baselines/reference/conditionalTypes2.types index 249c05f1ad3..5af4de235c8 100644 --- a/tests/baselines/reference/conditionalTypes2.types +++ b/tests/baselines/reference/conditionalTypes2.types @@ -444,3 +444,85 @@ function foo(value: T) { } } +// Repro from #23052 + +type A = +>A : A +>T : T +>V : V +>E : E + + T extends object +>T : T + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: A; } +>Q : Q +>P : P +>T : T +>T : T +>P : P +>V : V +>P : P +>P : P +>T : T +>A : A +>T : T +>Q : Q +>V : V +>E : E + + : T extends V ? T : never; +>T : T +>V : V +>T : T + +type B = +>B : B +>T : T +>V : V + + T extends object +>T : T + + ? { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: B; } +>Q : Q +>P : P +>T : T +>T : T +>P : P +>V : V +>P : P +>P : P +>T : T +>B : B +>T : T +>Q : Q +>V : V + + : T extends V ? T : never; +>T : T +>V : V +>T : T + +type C = +>C : C +>T : T +>V : V +>E : E + + { [Q in { [P in keyof T]: T[P] extends V ? P : P; }[keyof T]]: C; }; +>Q : Q +>P : P +>T : T +>T : T +>P : P +>V : V +>P : P +>P : P +>T : T +>C : C +>T : T +>Q : Q +>V : V +>E : E +