From 56aa3d522bce11f4bf1a8df868741da7e1a85fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 20 Mar 2023 19:10:31 +0100 Subject: [PATCH] Normalize generic tuple types with `Simplifiable` elements (#52385) --- src/compiler/checker.ts | 7 ++++ ...nericTupleWithSimplifiableElements.symbols | 42 +++++++++++++++++++ ...genericTupleWithSimplifiableElements.types | 40 ++++++++++++++++++ .../genericTupleWithSimplifiableElements.ts | 18 ++++++++ 4 files changed, 107 insertions(+) create mode 100644 tests/baselines/reference/genericTupleWithSimplifiableElements.symbols create mode 100644 tests/baselines/reference/genericTupleWithSimplifiableElements.types create mode 100644 tests/cases/compiler/genericTupleWithSimplifiableElements.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eb6b6d147aa..28a8a78ab73 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20126,6 +20126,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getNormalizedType(type: Type, writing: boolean): Type { while (true) { const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : + isGenericTupleType(type) ? getNormalizedTupleType(type, writing) : getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) : @@ -20150,6 +20151,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } + function getNormalizedTupleType(type: TupleTypeReference, writing: boolean): Type { + const elements = getTypeArguments(type); + const normalizedElements = sameMap(elements, t => t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t); + return elements !== normalizedElements ? createNormalizedTupleType(type.target, normalizedElements) : type; + } + /** * Checks if 'source' is related to 'target' (e.g.: is a assignable to). * @param source The left-hand-side of the relation. diff --git a/tests/baselines/reference/genericTupleWithSimplifiableElements.symbols b/tests/baselines/reference/genericTupleWithSimplifiableElements.symbols new file mode 100644 index 00000000000..80f6b4c749f --- /dev/null +++ b/tests/baselines/reference/genericTupleWithSimplifiableElements.symbols @@ -0,0 +1,42 @@ +=== tests/cases/compiler/genericTupleWithSimplifiableElements.ts === +// repro from #52354 + +type SS1 = string; +>SS1 : Symbol(SS1, Decl(genericTupleWithSimplifiableElements.ts, 0, 0)) + +let y: [t: "AAA", ...args: { [S in SS1]: [a: number]; }[SS1]] = ["AAA", 1]; +>y : Symbol(y, Decl(genericTupleWithSimplifiableElements.ts, 3, 3)) +>S : Symbol(S, Decl(genericTupleWithSimplifiableElements.ts, 3, 30)) +>SS1 : Symbol(SS1, Decl(genericTupleWithSimplifiableElements.ts, 0, 0)) +>SS1 : Symbol(SS1, Decl(genericTupleWithSimplifiableElements.ts, 0, 0)) + +type SS2 = "1" | "2" | "3"; +>SS2 : Symbol(SS2, Decl(genericTupleWithSimplifiableElements.ts, 3, 75)) + +let z: [t: "AAA", ...args: { [S in SS2]: [a: number]; }[SS2]] = ["AAA", 1]; +>z : Symbol(z, Decl(genericTupleWithSimplifiableElements.ts, 6, 3)) +>S : Symbol(S, Decl(genericTupleWithSimplifiableElements.ts, 6, 30)) +>SS2 : Symbol(SS2, Decl(genericTupleWithSimplifiableElements.ts, 3, 75)) +>SS2 : Symbol(SS2, Decl(genericTupleWithSimplifiableElements.ts, 3, 75)) + +class I{ +>I : Symbol(I, Decl(genericTupleWithSimplifiableElements.ts, 6, 75)) +>SS : Symbol(SS, Decl(genericTupleWithSimplifiableElements.ts, 8, 8)) + + f() { +>f : Symbol(I.f, Decl(genericTupleWithSimplifiableElements.ts, 8, 27)) + + let w: [...args: { [S in SS]: [a: number]; }[SS]] = [1]; +>w : Symbol(w, Decl(genericTupleWithSimplifiableElements.ts, 10, 11)) +>S : Symbol(S, Decl(genericTupleWithSimplifiableElements.ts, 10, 28)) +>SS : Symbol(SS, Decl(genericTupleWithSimplifiableElements.ts, 8, 8)) +>SS : Symbol(SS, Decl(genericTupleWithSimplifiableElements.ts, 8, 8)) + + let x: [t: "AAA", ...args: { [S in SS]: [a: number]; }[SS]] = ["AAA", 1]; +>x : Symbol(x, Decl(genericTupleWithSimplifiableElements.ts, 12, 11)) +>S : Symbol(S, Decl(genericTupleWithSimplifiableElements.ts, 12, 38)) +>SS : Symbol(SS, Decl(genericTupleWithSimplifiableElements.ts, 8, 8)) +>SS : Symbol(SS, Decl(genericTupleWithSimplifiableElements.ts, 8, 8)) + } +} + diff --git a/tests/baselines/reference/genericTupleWithSimplifiableElements.types b/tests/baselines/reference/genericTupleWithSimplifiableElements.types new file mode 100644 index 00000000000..c070bd23cb3 --- /dev/null +++ b/tests/baselines/reference/genericTupleWithSimplifiableElements.types @@ -0,0 +1,40 @@ +=== tests/cases/compiler/genericTupleWithSimplifiableElements.ts === +// repro from #52354 + +type SS1 = string; +>SS1 : string + +let y: [t: "AAA", ...args: { [S in SS1]: [a: number]; }[SS1]] = ["AAA", 1]; +>y : [t: "AAA", a: number] +>["AAA", 1] : ["AAA", number] +>"AAA" : "AAA" +>1 : 1 + +type SS2 = "1" | "2" | "3"; +>SS2 : "1" | "2" | "3" + +let z: [t: "AAA", ...args: { [S in SS2]: [a: number]; }[SS2]] = ["AAA", 1]; +>z : [t: "AAA", a: number] +>["AAA", 1] : ["AAA", number] +>"AAA" : "AAA" +>1 : 1 + +class I{ +>I : I + + f() { +>f : () => void + + let w: [...args: { [S in SS]: [a: number]; }[SS]] = [1]; +>w : [...args: { [S in SS]: [a: number]; }[SS]] +>[1] : [1] +>1 : 1 + + let x: [t: "AAA", ...args: { [S in SS]: [a: number]; }[SS]] = ["AAA", 1]; +>x : [t: "AAA", ...args: { [S in SS]: [a: number]; }[SS]] +>["AAA", 1] : ["AAA", 1] +>"AAA" : "AAA" +>1 : 1 + } +} + diff --git a/tests/cases/compiler/genericTupleWithSimplifiableElements.ts b/tests/cases/compiler/genericTupleWithSimplifiableElements.ts new file mode 100644 index 00000000000..dbad5c73fb3 --- /dev/null +++ b/tests/cases/compiler/genericTupleWithSimplifiableElements.ts @@ -0,0 +1,18 @@ +// @strict: true +// @noEmit: true + +// repro from #52354 + +type SS1 = string; +let y: [t: "AAA", ...args: { [S in SS1]: [a: number]; }[SS1]] = ["AAA", 1]; + +type SS2 = "1" | "2" | "3"; +let z: [t: "AAA", ...args: { [S in SS2]: [a: number]; }[SS2]] = ["AAA", 1]; + +class I{ + f() { + let w: [...args: { [S in SS]: [a: number]; }[SS]] = [1]; + + let x: [t: "AAA", ...args: { [S in SS]: [a: number]; }[SS]] = ["AAA", 1]; + } +}