From 81c2cb90e8c1beacd780d5e5b90cdfc15fa9ea8f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 9 Nov 2015 10:16:16 -0800 Subject: [PATCH] apply captured type parameters to returned classes Get instantiated constructors for classes with captured (outer) type parameters that have not yet been applied. The fast path was incorrect for these classes. --- src/compiler/checker.ts | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d1dbc966952..4f39ada7a53 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2868,23 +2868,25 @@ namespace ts { function resolveBaseTypesOfClass(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; - let baseContructorType = getBaseConstructorTypeOfClass(type); - if (!(baseContructorType.flags & TypeFlags.ObjectType)) { + let baseConstructorType = getBaseConstructorTypeOfClass(type); + if (!(baseConstructorType.flags & TypeFlags.ObjectType)) { return; } let baseTypeNode = getBaseTypeNodeOfClass(type); let baseType: Type; - if (baseContructorType.symbol && baseContructorType.symbol.flags & SymbolFlags.Class) { - // When base constructor type is a class we know that the constructors all have the same type parameters as the + let originalBaseType = baseConstructorType && baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; + if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && + !baseTypeHasUnappliedOuterTypeParameters(originalBaseType)) { + // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the // class and all return the instance type of the class. There is no need for further checks and we can apply the // type arguments in the same manner as a type reference to get the same error reporting experience. - baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseContructorType.symbol); + baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol); } else { // The class derives from a "class-like" constructor function, check that we have at least one construct signature // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere // we check that all instantiated signatures return the same type. - let constructors = getInstantiatedConstructorsForTypeArguments(baseContructorType, baseTypeNode.typeArguments); + let constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments); if (!constructors.length) { error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); return; @@ -2911,6 +2913,21 @@ namespace ts { } } + function baseTypeHasUnappliedOuterTypeParameters(type: Type): boolean { + let originalBaseType = type; + let originalTypeReference = type; + if (originalBaseType.outerTypeParameters) { + // an unapplied type type parameter is one + // whose argument symbol is still the same as the parameter symbol + for (let i = 0; i < originalBaseType.outerTypeParameters.length; i++) { + if (originalBaseType.outerTypeParameters[i].symbol === originalTypeReference.typeArguments[i].symbol) { + return true; + } + } + } + return false; + } + function resolveBaseTypesOfInterface(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; for (let declaration of type.symbol.declarations) {