From ca8c446d3f62769ac3a739a54164cccefe150142 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Mon, 26 Jan 2015 16:48:53 -0800 Subject: [PATCH] Use transient symbols when computing the indexers for object literals --- src/compiler/checker.ts | 20 ++++++++++++------- .../objectLiteralIndexerNoImplicitAny.js | 13 ++++++++++++ .../objectLiteralIndexerNoImplicitAny.types | 16 +++++++++++++++ .../objectLiteralIndexerNoImplicitAny.ts | 8 ++++++++ 4 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/objectLiteralIndexerNoImplicitAny.js create mode 100644 tests/baselines/reference/objectLiteralIndexerNoImplicitAny.types create mode 100644 tests/cases/compiler/objectLiteralIndexerNoImplicitAny.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fd85a477bd4..e5624fb8916 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5441,7 +5441,8 @@ module ts { // Grammar checking checkGrammarObjectLiteralExpression(node); - var properties: SymbolTable = {}; + var propertiesTable: SymbolTable = {}; + var propertiesArray: Symbol[] = []; var contextualType = getContextualType(node); var typeFlags: TypeFlags; @@ -5486,8 +5487,9 @@ module ts { } if (!hasDynamicName(memberDecl)) { - properties[member.name] = member; + propertiesTable[member.name] = member; } + propertiesArray.push(member); } // If object literal is contextually (but not inferentially) typed, copy missing optional properties from @@ -5495,25 +5497,29 @@ module ts { // were omitted. There is no need to create new property objects as nothing in them needs to change. if (contextualType && !isInferentialContext(contextualMapper)) { forEach(getPropertiesOfObjectType(contextualType), p => { - if (p.flags & SymbolFlags.Optional && !hasProperty(properties, p.name)) { - properties[p.name] = p; + if (p.flags & SymbolFlags.Optional && !hasProperty(propertiesTable, p.name)) { + propertiesTable[p.name] = p; } }); } var stringIndexType = getIndexType(IndexKind.String); var numberIndexType = getIndexType(IndexKind.Number); - var result = createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType); + var result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); result.flags |= (typeFlags & TypeFlags.Unwidened); return result; function getIndexType(kind: IndexKind) { if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { var propTypes: Type[] = []; - for (var i = 0; i < node.properties.length; i++) { + for (var i = 0; i < propertiesArray.length; i++) { var propertyDecl = node.properties[i]; if (kind === IndexKind.String || isNumericName(propertyDecl.name)) { - var type = getTypeOfSymbol(getSymbolOfNode(propertyDecl)); + // Do not call getSymbolOfNode(propertyDecl), as that will get the + // original symbol for the node. We actually want to get the symbol + // created by checkObjectLiteral, since that will be appropriately + // contextually typed and resolved. + var type = getTypeOfSymbol(propertiesArray[i]); if (!contains(propTypes, type)) { propTypes.push(type); } diff --git a/tests/baselines/reference/objectLiteralIndexerNoImplicitAny.js b/tests/baselines/reference/objectLiteralIndexerNoImplicitAny.js new file mode 100644 index 00000000000..2cbb76b200d --- /dev/null +++ b/tests/baselines/reference/objectLiteralIndexerNoImplicitAny.js @@ -0,0 +1,13 @@ +//// [objectLiteralIndexerNoImplicitAny.ts] +interface I { + [s: string]: any; +} + +var x: I = { + p: null +} + +//// [objectLiteralIndexerNoImplicitAny.js] +var x = { + p: null +}; diff --git a/tests/baselines/reference/objectLiteralIndexerNoImplicitAny.types b/tests/baselines/reference/objectLiteralIndexerNoImplicitAny.types new file mode 100644 index 00000000000..14bcc6f5b62 --- /dev/null +++ b/tests/baselines/reference/objectLiteralIndexerNoImplicitAny.types @@ -0,0 +1,16 @@ +=== tests/cases/compiler/objectLiteralIndexerNoImplicitAny.ts === +interface I { +>I : I + + [s: string]: any; +>s : string +} + +var x: I = { +>x : I +>I : I +>{ p: null} : { [x: string]: null; p: null; } + + p: null +>p : null +} diff --git a/tests/cases/compiler/objectLiteralIndexerNoImplicitAny.ts b/tests/cases/compiler/objectLiteralIndexerNoImplicitAny.ts new file mode 100644 index 00000000000..c21d8df52fc --- /dev/null +++ b/tests/cases/compiler/objectLiteralIndexerNoImplicitAny.ts @@ -0,0 +1,8 @@ +//@noImplicitAny: true +interface I { + [s: string]: any; +} + +var x: I = { + p: null +} \ No newline at end of file