Support local generic types within generic classes and functions

This commit is contained in:
Anders Hejlsberg
2015-05-24 16:02:28 -07:00
parent cf40696040
commit 10e940ad55
4 changed files with 62 additions and 32 deletions
+60 -27
View File
@@ -2465,30 +2465,61 @@ module ts {
}
}
function appendTypeParameters(typeParameters: TypeParameter[], declarations: TypeParameterDeclaration[]): TypeParameter[] {
for (let declaration of declarations) {
let tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration));
if (!typeParameters) {
typeParameters = [tp];
}
else if (!contains(typeParameters, tp)) {
typeParameters.push(tp);
}
}
return typeParameters;
}
function appendOuterTypeParameters(typeParameters: TypeParameter[], node: Node): TypeParameter[]{
while (true) {
node = node.parent;
if (!node) {
return typeParameters;
}
if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.FunctionDeclaration ||
node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.MethodDeclaration ||
node.kind === SyntaxKind.ArrowFunction) {
let declarations = (<ClassDeclaration | FunctionLikeDeclaration>node).typeParameters;
if (declarations) {
return appendTypeParameters(appendOuterTypeParameters(typeParameters, node), declarations);
}
}
}
}
function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
var kind = symbol.flags & SymbolFlags.Class ? SyntaxKind.ClassDeclaration : SyntaxKind.InterfaceDeclaration;
return appendOuterTypeParameters(undefined, getDeclarationOfKind(symbol, kind));
}
// Return combined list of type parameters from all declarations of a class or interface. Elsewhere we check they're all
// the same, but even if they're not we still need the complete list to ensure instantiations supply type arguments
// for all type parameters.
function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
function getLocalTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
let result: TypeParameter[];
forEach(symbol.declarations, node => {
for (let node of symbol.declarations) {
if (node.kind === SyntaxKind.InterfaceDeclaration || node.kind === SyntaxKind.ClassDeclaration) {
let declaration = <InterfaceDeclaration>node;
if (declaration.typeParameters && declaration.typeParameters.length) {
forEach(declaration.typeParameters, node => {
let tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
if (!result) {
result = [tp];
}
else if (!contains(result, tp)) {
result.push(tp);
}
});
if (declaration.typeParameters) {
result = appendTypeParameters(result, declaration.typeParameters);
}
}
});
}
return result;
}
function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterface(symbol));
}
function getBaseTypes(type: InterfaceType): ObjectType[] {
let typeWithBaseTypes = <InterfaceTypeWithBaseTypes>type;
if (!typeWithBaseTypes.baseTypes) {
@@ -2558,10 +2589,13 @@ module ts {
if (!links.declaredType) {
let kind = symbol.flags & SymbolFlags.Class ? TypeFlags.Class : TypeFlags.Interface;
let type = links.declaredType = <InterfaceType>createObjectType(kind, symbol);
let typeParameters = getTypeParametersOfClassOrInterface(symbol);
if (typeParameters) {
let outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol);
let localTypeParameters = getLocalTypeParametersOfClassOrInterface(symbol);
if (outerTypeParameters || localTypeParameters) {
type.flags |= TypeFlags.Reference;
type.typeParameters = typeParameters;
type.typeParameters = concatenate(outerTypeParameters, localTypeParameters);
type.outerTypeParameters = outerTypeParameters;
type.localTypeParameters = localTypeParameters;
(<GenericType>type).instantiations = {};
(<GenericType>type).instantiations[getTypeListId(type.typeParameters)] = <GenericType>type;
(<GenericType>type).target = <GenericType>type;
@@ -2751,12 +2785,12 @@ module ts {
return map(baseSignatures, baseSignature => {
let signature = baseType.flags & TypeFlags.Reference ?
getSignatureInstantiation(baseSignature, (<TypeReference>baseType).typeArguments) : cloneSignature(baseSignature);
signature.typeParameters = classType.typeParameters;
signature.typeParameters = classType.localTypeParameters;
signature.resolvedReturnType = classType;
return signature;
});
}
return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)];
return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, false, false)];
}
function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
@@ -3105,7 +3139,7 @@ module ts {
let links = getNodeLinks(declaration);
if (!links.resolvedSignature) {
let classType = declaration.kind === SyntaxKind.Constructor ? getDeclaredTypeOfClassOrInterface((<ClassDeclaration>declaration.parent).symbol) : undefined;
let typeParameters = classType ? classType.typeParameters :
let typeParameters = classType ? classType.localTypeParameters :
declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : undefined;
let parameters: Symbol[] = [];
let hasStringLiterals = false;
@@ -3423,11 +3457,14 @@ module ts {
type = getDeclaredTypeOfSymbol(symbol);
if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) {
let typeParameters = (<InterfaceType>type).typeParameters;
if (node.typeArguments && node.typeArguments.length === typeParameters.length) {
type = createTypeReference(<GenericType>type, map(node.typeArguments, getTypeFromTypeNode));
let outerTypeParameters = (<InterfaceType>type).outerTypeParameters;
let expectedTypeArgCount = typeParameters.length - (outerTypeParameters ? outerTypeParameters.length : 0);
let typeArgCount = node.typeArguments ? node.typeArguments.length : 0;
if (typeArgCount === expectedTypeArgCount) {
type = createTypeReference(<GenericType>type, concatenate(outerTypeParameters, map(node.typeArguments, getTypeFromTypeNode)));
}
else {
error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), expectedTypeArgCount);
type = undefined;
}
}
@@ -3884,7 +3921,7 @@ module ts {
return mapper(<TypeParameter>type);
}
if (type.flags & TypeFlags.Anonymous) {
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ?
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ?
instantiateAnonymousType(<ObjectType>type, mapper) : type;
}
if (type.flags & TypeFlags.Reference) {
@@ -9991,10 +10028,6 @@ module ts {
function checkClassDeclaration(node: ClassDeclaration) {
checkGrammarDeclarationNameInStrictMode(node);
// Grammar checking
if (node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
grammarErrorOnNode(node, Diagnostics.class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration);
}
if (!node.name && !(node.flags & NodeFlags.Default)) {
grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name);
}
@@ -544,6 +544,5 @@ module ts {
Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported." },
Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." },
class_expressions_are_not_currently_supported: { code: 9003, category: DiagnosticCategory.Error, key: "'class' expressions are not currently supported." },
class_declarations_are_only_supported_directly_inside_a_module_or_as_a_top_level_declaration: { code: 9004, category: DiagnosticCategory.Error, key: "'class' declarations are only supported directly inside a module or as a top level declaration." },
};
}
-4
View File
@@ -2168,9 +2168,5 @@
"'class' expressions are not currently supported.": {
"category": "Error",
"code": 9003
},
"'class' declarations are only supported directly inside a module or as a top level declaration.": {
"category": "Error",
"code": 9004
}
}
+2
View File
@@ -1499,6 +1499,8 @@ module ts {
// Class and interface types (TypeFlags.Class and TypeFlags.Interface)
export interface InterfaceType extends ObjectType {
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none)
localTypeParameters: TypeParameter[]; // Local type parameters (undefined if none)
}
export interface InterfaceTypeWithBaseTypes extends InterfaceType {