From 4fc94287dc8472a9c26a66b477bedcda4db35b32 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 22 Feb 2019 14:51:31 -0800 Subject: [PATCH] Retain substitution types through instantiation if possible --- src/compiler/checker.ts | 11 ++- ...dAliasAssignableToConstraintSameAsAlias.js | 36 ++++++++ ...sAssignableToConstraintSameAsAlias.symbols | 85 +++++++++++++++++++ ...iasAssignableToConstraintSameAsAlias.types | 45 ++++++++++ ...dAliasAssignableToConstraintSameAsAlias.ts | 24 ++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.js create mode 100644 tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.symbols create mode 100644 tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.types create mode 100644 tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 958ceae0395a2..ddc958df0b41f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11062,7 +11062,13 @@ namespace ts { return getConditionalTypeInstantiation(type, combineTypeMappers((type).mapper, mapper)); } if (flags & TypeFlags.Substitution) { - return instantiateType((type).typeVariable, mapper); + const maybeVariable = instantiateType((type).typeVariable, mapper); + if (maybeVariable.flags & TypeFlags.TypeVariable) { + return getSubstitutionType(maybeVariable as TypeVariable, instantiateType((type).substitute, mapper)); + } + else { + return maybeVariable; + } } return type; } @@ -14465,6 +14471,9 @@ namespace ts { } } } + else if (target.flags & TypeFlags.Substitution) { + inferFromTypes(source, (target as SubstitutionType).typeVariable); + } if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // If source and target are references to the same generic type, infer from type arguments const sourceTypes = (source).typeArguments || emptyArray; diff --git a/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.js b/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.js new file mode 100644 index 0000000000000..2d82034c6f7c9 --- /dev/null +++ b/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.js @@ -0,0 +1,36 @@ +//// [inlinedAliasAssignableToConstraintSameAsAlias.ts] +interface RelationFields { + x: A; + y: A[]; + z: A[]; +} +type Name = keyof RelationFields; +type ShouldA = RF[N] extends A[] + ? RF[N][0] + : never; + +class A { + x: A; + y: A[]; + z: A[]; + + whereRelated< // Works // Type is same as A1, but is not assignable to type A + RF extends RelationFields = RelationFields, + N extends Name = Name, + A1 extends A = RF[N] extends A[] ? RF[N][0] : never, + A2 extends A = ShouldA + >(): number { + return 1; + } +} + + +//// [inlinedAliasAssignableToConstraintSameAsAlias.js] +var A = /** @class */ (function () { + function A() { + } + A.prototype.whereRelated = function () { + return 1; + }; + return A; +}()); diff --git a/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.symbols b/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.symbols new file mode 100644 index 0000000000000..86e55f14ee924 --- /dev/null +++ b/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.symbols @@ -0,0 +1,85 @@ +=== tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts === +interface RelationFields { +>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0)) + + x: A; +>x : Symbol(RelationFields.x, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 26)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + y: A[]; +>y : Symbol(RelationFields.y, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 1, 7)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + z: A[]; +>z : Symbol(RelationFields.z, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 2, 9)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) +} +type Name = keyof RelationFields; +>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1)) +>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0)) + +type ShouldA = RF[N] extends A[] +>ShouldA : Symbol(ShouldA, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 5, 33)) +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 13)) +>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0)) +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 39)) +>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1)) +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 13)) +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 39)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + ? RF[N][0] +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 13)) +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 6, 39)) + + : never; + +class A { +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + x: A; +>x : Symbol(A.x, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 10, 9)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + y: A[]; +>y : Symbol(A.y, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 11, 7)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + z: A[]; +>z : Symbol(A.z, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 12, 9)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) + + whereRelated< // Works // Type is same as A1, but is not assignable to type A +>whereRelated : Symbol(A.whereRelated, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 13, 9)) + + RF extends RelationFields = RelationFields, +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15)) +>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0)) +>RelationFields : Symbol(RelationFields, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 0, 0)) + + N extends Name = Name, +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47)) +>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1)) +>Name : Symbol(Name, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 4, 1)) + + A1 extends A = RF[N] extends A[] ? RF[N][0] : never, +>A1 : Symbol(A1, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 17, 26)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15)) +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15)) +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47)) + + A2 extends A = ShouldA +>A2 : Symbol(A2, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 18, 56)) +>A : Symbol(A, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 8, 10)) +>ShouldA : Symbol(ShouldA, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 5, 33)) +>RF : Symbol(RF, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 15, 15)) +>N : Symbol(N, Decl(inlinedAliasAssignableToConstraintSameAsAlias.ts, 16, 47)) + + >(): number { + return 1; + } +} + diff --git a/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.types b/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.types new file mode 100644 index 0000000000000..d337fbc718abb --- /dev/null +++ b/tests/baselines/reference/inlinedAliasAssignableToConstraintSameAsAlias.types @@ -0,0 +1,45 @@ +=== tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts === +interface RelationFields { + x: A; +>x : A + + y: A[]; +>y : A[] + + z: A[]; +>z : A[] +} +type Name = keyof RelationFields; +>Name : "x" | "y" | "z" + +type ShouldA = RF[N] extends A[] +>ShouldA : ShouldA + + ? RF[N][0] + : never; + +class A { +>A : A + + x: A; +>x : A + + y: A[]; +>y : A[] + + z: A[]; +>z : A[] + + whereRelated< // Works // Type is same as A1, but is not assignable to type A +>whereRelated : >() => number + + RF extends RelationFields = RelationFields, + N extends Name = Name, + A1 extends A = RF[N] extends A[] ? RF[N][0] : never, + A2 extends A = ShouldA + >(): number { + return 1; +>1 : 1 + } +} + diff --git a/tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts b/tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts new file mode 100644 index 0000000000000..165ec0dc17e16 --- /dev/null +++ b/tests/cases/compiler/inlinedAliasAssignableToConstraintSameAsAlias.ts @@ -0,0 +1,24 @@ +interface RelationFields { + x: A; + y: A[]; + z: A[]; +} +type Name = keyof RelationFields; +type ShouldA = RF[N] extends A[] + ? RF[N][0] + : never; + +class A { + x: A; + y: A[]; + z: A[]; + + whereRelated< // Works // Type is same as A1, but is not assignable to type A + RF extends RelationFields = RelationFields, + N extends Name = Name, + A1 extends A = RF[N] extends A[] ? RF[N][0] : never, + A2 extends A = ShouldA + >(): number { + return 1; + } +}