From 442ad4b032eae2df0a7a6b2f3302362e87e9158b Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 25 Jul 2014 12:06:18 -0700 Subject: [PATCH 1/4] use symbol links to access global array type --- src/compiler/checker.ts | 38 ++++++++++++++++++----- tests/baselines/reference/augmentArray.js | 6 ++++ tests/cases/compiler/augmentArray.ts | 3 ++ 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/augmentArray.js create mode 100644 tests/cases/compiler/augmentArray.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9f1b0abaecf..056879f099a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -43,9 +43,10 @@ module ts { var globals: SymbolTable = {}; + var globalArrayTypeSymbolLinks: SymbolLinks; + var globalObjectType: ObjectType; var globalFunctionType: ObjectType; - var globalArrayType: ObjectType; var globalStringType: ObjectType; var globalNumberType: ObjectType; var globalBooleanType: ObjectType; @@ -773,7 +774,7 @@ module ts { } function writeTypeReference(type: TypeReference) { - if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { + if (type.target === globalArrayTypeSymbolLinks.declaredType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { // If we are writing array element type the arrow style signatures are not allowed as // we need to surround it by curlies, eg. { (): T; }[]; as () => T[] would mean something different writeType(type.typeArguments[0], /*allowFunctionOrConstructorTypeLiteral*/ false); @@ -1805,7 +1806,7 @@ module ts { function getRestTypeOfSignature(signature: Signature): Type { if (signature.hasRestParameter) { var type = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); - if (type.flags & TypeFlags.Reference && (type).target === globalArrayType) { + if (type.flags & TypeFlags.Reference && (type).target === globalArrayTypeSymbolLinks.declaredType) { return (type).typeArguments[0]; } } @@ -2016,8 +2017,11 @@ module ts { return links.resolvedType; } - function getGlobalType(name: string, arity: number = 0): ObjectType { + function resolveGlobalTypeSymbol(name: string): Symbol { + return resolveName(undefined, name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0, name); + } + function resolveGlobalType(symbol: Symbol, arity: number): ObjectType { function getTypeDeclaration(symbol: Symbol): Declaration { var declarations = symbol.declarations; for (var i = 0; i < declarations.length; i++) { @@ -2032,8 +2036,6 @@ module ts { } } } - - var symbol = resolveName(undefined, name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0, name); if (!symbol) { return emptyObjectType; } @@ -2049,7 +2051,12 @@ module ts { return type; } + function getGlobalType(name: string, arity: number = 0): ObjectType { + return resolveGlobalType(resolveGlobalTypeSymbol(name), arity); + } + function createArrayType(elementType: Type): Type { + var globalArrayType = globalArrayTypeSymbolLinks.declaredType; return globalArrayType !== emptyObjectType ? createTypeReference(globalArrayType, [elementType]) : emptyObjectType; } @@ -2944,7 +2951,7 @@ module ts { } function isArrayType(type: Type): boolean { - return type.flags & TypeFlags.Reference && (type).target === globalArrayType; + return type.flags & TypeFlags.Reference && (type).target === globalArrayTypeSymbolLinks.declaredType; } function getInnermostTypeOfNestedArrayTypes(type: Type): Type { @@ -6282,9 +6289,24 @@ module ts { getSymbolLinks(unknownSymbol).type = unknownType; globals[undefinedSymbol.name] = undefinedSymbol; // Initialize special types + // Initialize array type. + // Note: + // if user code extends Array type so extension contains signatures that involve arrays (sample below) + // then just calling getGlobalType(Array) will try to access globalArrayType before it is initialized + // to handle this instead of storing Array as type we store SymbolLinks for Array symbol and access type as links.declaredType. + // interface Array { (): any[] } + // + var globalArraySymbol = resolveGlobalTypeSymbol("Array"); + if (!globalArraySymbol) { + globalArrayTypeSymbolLinks = { declaredType: emptyObjectType }; + } + else { + globalArrayTypeSymbolLinks = getSymbolLinks(globalArraySymbol); + globalArrayTypeSymbolLinks.declaredType = resolveGlobalType(globalArraySymbol, 1); + } + globalObjectType = getGlobalType("Object"); globalFunctionType = getGlobalType("Function"); - globalArrayType = getGlobalType("Array", 1); globalStringType = getGlobalType("String"); globalNumberType = getGlobalType("Number"); globalBooleanType = getGlobalType("Boolean"); diff --git a/tests/baselines/reference/augmentArray.js b/tests/baselines/reference/augmentArray.js new file mode 100644 index 00000000000..948f1944048 --- /dev/null +++ b/tests/baselines/reference/augmentArray.js @@ -0,0 +1,6 @@ +//// [augmentArray.ts] +interface Array { + (): any[]; +} + +//// [augmentArray.js] diff --git a/tests/cases/compiler/augmentArray.ts b/tests/cases/compiler/augmentArray.ts new file mode 100644 index 00000000000..e2ab81db941 --- /dev/null +++ b/tests/cases/compiler/augmentArray.ts @@ -0,0 +1,3 @@ +interface Array { + (): any[]; +} \ No newline at end of file From 956b6398e02a59cdc8d0ca5baffa54cb32adf9b6 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 25 Jul 2014 16:42:09 -0700 Subject: [PATCH 2/4] localize special case (globalArrayType === undefined) in getTypeFromArrayTypeNode --- src/compiler/checker.ts | 52 +++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 056879f099a..dba1dab5d7c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -43,10 +43,9 @@ module ts { var globals: SymbolTable = {}; - var globalArrayTypeSymbolLinks: SymbolLinks; - var globalObjectType: ObjectType; var globalFunctionType: ObjectType; + var globalArrayType: ObjectType; var globalStringType: ObjectType; var globalNumberType: ObjectType; var globalBooleanType: ObjectType; @@ -774,7 +773,7 @@ module ts { } function writeTypeReference(type: TypeReference) { - if (type.target === globalArrayTypeSymbolLinks.declaredType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { + if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { // If we are writing array element type the arrow style signatures are not allowed as // we need to surround it by curlies, eg. { (): T; }[]; as () => T[] would mean something different writeType(type.typeArguments[0], /*allowFunctionOrConstructorTypeLiteral*/ false); @@ -1806,7 +1805,7 @@ module ts { function getRestTypeOfSignature(signature: Signature): Type { if (signature.hasRestParameter) { var type = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); - if (type.flags & TypeFlags.Reference && (type).target === globalArrayTypeSymbolLinks.declaredType) { + if (type.flags & TypeFlags.Reference && (type).target === globalArrayType) { return (type).typeArguments[0]; } } @@ -2017,11 +2016,8 @@ module ts { return links.resolvedType; } - function resolveGlobalTypeSymbol(name: string): Symbol { - return resolveName(undefined, name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0, name); - } + function getGlobalType(name: string, arity: number = 0): ObjectType { - function resolveGlobalType(symbol: Symbol, arity: number): ObjectType { function getTypeDeclaration(symbol: Symbol): Declaration { var declarations = symbol.declarations; for (var i = 0; i < declarations.length; i++) { @@ -2036,6 +2032,8 @@ module ts { } } } + + var symbol = resolveName(undefined, name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0, name); if (!symbol) { return emptyObjectType; } @@ -2051,19 +2049,22 @@ module ts { return type; } - function getGlobalType(name: string, arity: number = 0): ObjectType { - return resolveGlobalType(resolveGlobalTypeSymbol(name), arity); - } - - function createArrayType(elementType: Type): Type { - var globalArrayType = globalArrayTypeSymbolLinks.declaredType; - return globalArrayType !== emptyObjectType ? createTypeReference(globalArrayType, [elementType]) : emptyObjectType; + function createArrayType(elementType: Type, arrayType?: ObjectType): Type { + var type = globalArrayType || arrayType; + return type !== emptyObjectType ? createTypeReference(type, [elementType]) : emptyObjectType; } function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type { var links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType)); + var arrayType = globalArrayType; + if (!arrayType) { + var arrayTypeSymbol = resolveName(node, "Array", SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); + Debug.assert(arrayTypeSymbol); + arrayType = getDeclaredTypeOfSymbol(arrayTypeSymbol); + Debug.assert(arrayType); + } + links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType), arrayType); } return links.resolvedType; } @@ -2951,7 +2952,7 @@ module ts { } function isArrayType(type: Type): boolean { - return type.flags & TypeFlags.Reference && (type).target === globalArrayTypeSymbolLinks.declaredType; + return type.flags & TypeFlags.Reference && (type).target === globalArrayType; } function getInnermostTypeOfNestedArrayTypes(type: Type): Type { @@ -6289,22 +6290,7 @@ module ts { getSymbolLinks(unknownSymbol).type = unknownType; globals[undefinedSymbol.name] = undefinedSymbol; // Initialize special types - // Initialize array type. - // Note: - // if user code extends Array type so extension contains signatures that involve arrays (sample below) - // then just calling getGlobalType(Array) will try to access globalArrayType before it is initialized - // to handle this instead of storing Array as type we store SymbolLinks for Array symbol and access type as links.declaredType. - // interface Array { (): any[] } - // - var globalArraySymbol = resolveGlobalTypeSymbol("Array"); - if (!globalArraySymbol) { - globalArrayTypeSymbolLinks = { declaredType: emptyObjectType }; - } - else { - globalArrayTypeSymbolLinks = getSymbolLinks(globalArraySymbol); - globalArrayTypeSymbolLinks.declaredType = resolveGlobalType(globalArraySymbol, 1); - } - + globalArrayType = getGlobalType("Array", 1); globalObjectType = getGlobalType("Object"); globalFunctionType = getGlobalType("Function"); globalStringType = getGlobalType("String"); From 6fe8acb103e48d99f416786870ae01c5f882e735 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 25 Jul 2014 16:49:35 -0700 Subject: [PATCH 3/4] added comments --- src/compiler/checker.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dba1dab5d7c..00866c4891e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2059,6 +2059,10 @@ module ts { if (!links.resolvedType) { var arrayType = globalArrayType; if (!arrayType) { + // if user code contains augmentation for Array type that includes call\construct signatures with arrays as parameter\return types, + // then we might step here then during initialization of the global Array type when globalArrayType is not yet set. + // CODE: interface Array { (): number[] } + // in this case just resolve name 'Array' again and get declared type of symbol var arrayTypeSymbol = resolveName(node, "Array", SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); Debug.assert(arrayTypeSymbol); arrayType = getDeclaredTypeOfSymbol(arrayTypeSymbol); From a2210184be980ad26b1249588b8ac3ef5794ffc8 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 25 Jul 2014 17:08:35 -0700 Subject: [PATCH 4/4] comments updated --- src/compiler/checker.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 00866c4891e..4037a5fd2cc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2049,9 +2049,10 @@ module ts { return type; } + // arrayType argument is used as a backup in case if globalArrayType is not defined function createArrayType(elementType: Type, arrayType?: ObjectType): Type { - var type = globalArrayType || arrayType; - return type !== emptyObjectType ? createTypeReference(type, [elementType]) : emptyObjectType; + var rootType = globalArrayType || arrayType; + return rootType !== emptyObjectType ? createTypeReference(rootType, [elementType]) : emptyObjectType; } function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type { @@ -2062,7 +2063,9 @@ module ts { // if user code contains augmentation for Array type that includes call\construct signatures with arrays as parameter\return types, // then we might step here then during initialization of the global Array type when globalArrayType is not yet set. // CODE: interface Array { (): number[] } - // in this case just resolve name 'Array' again and get declared type of symbol + // in this case just resolve name 'Array' again and get declared type of symbol. + // this type is the one that eventually should be set as 'globalArrayType'. + // NOTE: this is specific to signatures since got signatures we realize parameter\return types. var arrayTypeSymbol = resolveName(node, "Array", SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); Debug.assert(arrayTypeSymbol); arrayType = getDeclaredTypeOfSymbol(arrayTypeSymbol);