From a437c0a6893cb1625123c1b482ba934391af2a80 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 30 Dec 2016 18:27:38 -0800 Subject: [PATCH 1/3] Fix homomorphic type check in instantiateMappedType --- src/compiler/checker.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 22dec25324d..38feb249b76 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6628,17 +6628,19 @@ namespace ts { const constraintType = getConstraintTypeFromMappedType(type); if (constraintType.flags & TypeFlags.Index) { const typeVariable = (constraintType).type; - const mappedTypeVariable = instantiateType(typeVariable, mapper); - if (typeVariable !== mappedTypeVariable) { - return mapType(mappedTypeVariable, t => { - if (isMappableType(t)) { - const replacementMapper = createUnaryTypeMapper(typeVariable, t); - const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper); - combinedMapper.mappedTypes = mapper.mappedTypes; - return instantiateMappedObjectType(type, combinedMapper); - } - return t; - }); + if (typeVariable.flags & TypeFlags.TypeParameter) { + const mappedTypeVariable = instantiateType(typeVariable, mapper); + if (typeVariable !== mappedTypeVariable) { + return mapType(mappedTypeVariable, t => { + if (isMappableType(t)) { + const replacementMapper = createUnaryTypeMapper(typeVariable, t); + const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper); + combinedMapper.mappedTypes = mapper.mappedTypes; + return instantiateMappedObjectType(type, combinedMapper); + } + return t; + }); + } } } return instantiateMappedObjectType(type, mapper); From bb37a61f61884fb7f2283af45e5fb78e02ee611e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 30 Dec 2016 18:48:16 -0800 Subject: [PATCH 2/3] Add regression test --- .../cases/conformance/types/mapped/mappedTypes4.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/cases/conformance/types/mapped/mappedTypes4.ts b/tests/cases/conformance/types/mapped/mappedTypes4.ts index 74b3e395f32..4def192d602 100644 --- a/tests/cases/conformance/types/mapped/mappedTypes4.ts +++ b/tests/cases/conformance/types/mapped/mappedTypes4.ts @@ -59,4 +59,15 @@ type DeepReadonlyFoo = { }; var x1: DeepReadonly; -var x1: DeepReadonlyFoo; \ No newline at end of file +var x1: DeepReadonlyFoo; + +// Repro from #13232 + +type Z = { a: number }; +type Clone = { + [P in keyof (T & {})]: T[P]; +}; +type M = Clone; // M should be { a: number } + +var z1: Z; +var z1: Clone; From c0bf7de08283e496b07f6e4173d20e4e54df158d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 30 Dec 2016 18:48:23 -0800 Subject: [PATCH 3/3] Accept new baselines --- tests/baselines/reference/mappedTypes4.js | 25 ++++++++++++++- .../baselines/reference/mappedTypes4.symbols | 31 +++++++++++++++++++ tests/baselines/reference/mappedTypes4.types | 31 +++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/mappedTypes4.js b/tests/baselines/reference/mappedTypes4.js index bb003b1a1ec..963538d2269 100644 --- a/tests/baselines/reference/mappedTypes4.js +++ b/tests/baselines/reference/mappedTypes4.js @@ -58,7 +58,19 @@ type DeepReadonlyFoo = { }; var x1: DeepReadonly; -var x1: DeepReadonlyFoo; +var x1: DeepReadonlyFoo; + +// Repro from #13232 + +type Z = { a: number }; +type Clone = { + [P in keyof (T & {})]: T[P]; +}; +type M = Clone; // M should be { a: number } + +var z1: Z; +var z1: Clone; + //// [mappedTypes4.js] function boxify(obj) { @@ -76,6 +88,8 @@ function f1(x) { } var x1; var x1; +var z1; +var z1; //// [mappedTypes4.d.ts] @@ -127,3 +141,12 @@ declare type DeepReadonlyFoo = { }; declare var x1: DeepReadonly; declare var x1: DeepReadonlyFoo; +declare type Z = { + a: number; +}; +declare type Clone = { + [P in keyof (T & {})]: T[P]; +}; +declare type M = Clone; +declare var z1: Z; +declare var z1: Clone; diff --git a/tests/baselines/reference/mappedTypes4.symbols b/tests/baselines/reference/mappedTypes4.symbols index b57adfe9954..ed108b47d78 100644 --- a/tests/baselines/reference/mappedTypes4.symbols +++ b/tests/baselines/reference/mappedTypes4.symbols @@ -196,3 +196,34 @@ var x1: DeepReadonlyFoo; >x1 : Symbol(x1, Decl(mappedTypes4.ts, 58, 3), Decl(mappedTypes4.ts, 59, 3)) >DeepReadonlyFoo : Symbol(DeepReadonlyFoo, Decl(mappedTypes4.ts, 50, 2)) +// Repro from #13232 + +type Z = { a: number }; +>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24)) +>a : Symbol(a, Decl(mappedTypes4.ts, 63, 10)) + +type Clone = { +>Clone : Symbol(Clone, Decl(mappedTypes4.ts, 63, 23)) +>T : Symbol(T, Decl(mappedTypes4.ts, 64, 11)) + + [P in keyof (T & {})]: T[P]; +>P : Symbol(P, Decl(mappedTypes4.ts, 65, 3)) +>T : Symbol(T, Decl(mappedTypes4.ts, 64, 11)) +>T : Symbol(T, Decl(mappedTypes4.ts, 64, 11)) +>P : Symbol(P, Decl(mappedTypes4.ts, 65, 3)) + +}; +type M = Clone; // M should be { a: number } +>M : Symbol(M, Decl(mappedTypes4.ts, 66, 2)) +>Clone : Symbol(Clone, Decl(mappedTypes4.ts, 63, 23)) +>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24)) + +var z1: Z; +>z1 : Symbol(z1, Decl(mappedTypes4.ts, 69, 3), Decl(mappedTypes4.ts, 70, 3)) +>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24)) + +var z1: Clone; +>z1 : Symbol(z1, Decl(mappedTypes4.ts, 69, 3), Decl(mappedTypes4.ts, 70, 3)) +>Clone : Symbol(Clone, Decl(mappedTypes4.ts, 63, 23)) +>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24)) + diff --git a/tests/baselines/reference/mappedTypes4.types b/tests/baselines/reference/mappedTypes4.types index cc492d82120..a2fec06ccec 100644 --- a/tests/baselines/reference/mappedTypes4.types +++ b/tests/baselines/reference/mappedTypes4.types @@ -211,3 +211,34 @@ var x1: DeepReadonlyFoo; >x1 : DeepReadonly >DeepReadonlyFoo : DeepReadonlyFoo +// Repro from #13232 + +type Z = { a: number }; +>Z : Z +>a : number + +type Clone = { +>Clone : Clone +>T : T + + [P in keyof (T & {})]: T[P]; +>P : P +>T : T +>T : T +>P : P + +}; +type M = Clone; // M should be { a: number } +>M : Clone +>Clone : Clone +>Z : Z + +var z1: Z; +>z1 : Z +>Z : Z + +var z1: Clone; +>z1 : Z +>Clone : Clone +>Z : Z +