From e96ec8c2c7bb6ea85610c9462bf6b07ed8b4c7cc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 Jan 2018 12:51:24 -0800 Subject: [PATCH] Erase substitution types in type references and type alias instantiations --- src/compiler/checker.ts | 10 ++++++++++ src/compiler/types.ts | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6abe6ad04b0..4f3a6225d88 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7316,7 +7316,16 @@ namespace ts { return result & TypeFlags.PropagatingFlags; } + // This function replaces substitution types in the given array with their underlying type parameter. + // We do this when creating type references and type alias instantiations because subsitution types are + // no longer necessary once the type arguments have been validated against their corresponding type + // parameter constraints. + function eraseSubstitutionTypes(types: Type[]) { + return sameMap(types, t => t.flags & TypeFlags.Substitution ? (t).typeParameter : t); + } + function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { + typeArguments = eraseSubstitutionTypes(typeArguments); const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { @@ -7383,6 +7392,7 @@ namespace ts { } function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type { + typeArguments = eraseSubstitutionTypes(typeArguments); const type = getDeclaredTypeOfSymbol(symbol); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f426370002b..c544334b7dd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3703,6 +3703,10 @@ namespace ts { } // Type parameter substitution (TypeFlags.Substitution) + // Substitution types are created for type parameter references that occur in the true branch + // of a conditional type. For example, in 'T extends string ? Foo : Bar', the reference to + // T in Foo is resolved as a substitution type that substitutes 'string & T' for T. Thus, if + // Foo has a 'string' constraint on its type parameter, T will satisfy it. export interface SubstitutionType extends InstantiableType { typeParameter: TypeParameter; // Target type parameter substitute: Type; // Type to substitute for type parameter