From 05500f4577aa7761e46dc5ddcbd3a2e644c4c079 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 1 Jun 2015 14:49:11 -0700 Subject: [PATCH] Added merged declarations for ambient class/interfaces --- src/compiler/binder.ts | 42 +++++++++++++++++++++++++++++++----------- src/compiler/types.ts | 3 ++- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b66497fc40d..15370d5e9db 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -6,8 +6,8 @@ module ts { export const enum ModuleInstanceState { NonInstantiated = 0, - Instantiated = 1, - ConstEnumOnly = 2 + Instantiated = 1, + ConstEnumOnly = 2 } export function getModuleInstanceState(node: Node): ModuleInstanceState { @@ -135,6 +135,26 @@ module ts { return node.name ? declarationNameToString(node.name) : getDeclarationName(node); } + /* internal */ + /** + * Checks if the symbol contains a class declaration declaration that is non-ambient. + */ + function hasNonAmbientClass(symbol: Symbol): boolean { + if (symbol) { + return !! forEach(symbol.declarations, (element: Declaration, index: number) => { + return (element.kind === SyntaxKind.ClassDeclaration && !(element.flags & NodeFlags.Ambient)) + }); + } + } + + /** + * Declares a Symbol for the Node and add it to symbols. Reports errors for conflicting identifier names, + * @param symbols - The symbolTable which node will be added to. + * @param parent - If node is in a class, parent denotes the parent declaration. + * @param node - The declaration to be added to the symbol table + * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.) + * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations. + */ function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { Debug.assert(!hasDynamicName(node)); @@ -144,15 +164,15 @@ module ts { let symbol: Symbol; if (name !== undefined) { symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(0, name)); - if (symbol.flags & excludes) { - if (node.name) { - node.name.parent = node; - } + if (symbol.flags & excludes || (node.kind === SyntaxKind.InterfaceDeclaration && hasNonAmbientClass(symbol)) ) { + if (node.name) { + node.name.parent = node; + } // Report errors every position with duplicate declaration // Report errors on previous encountered declarations let message = symbol.flags & SymbolFlags.BlockScopedVariable - ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; forEach(symbol.declarations, declaration => { @@ -249,7 +269,7 @@ module ts { // these cases are: // - node has locals (symbolKind & HasLocals) !== 0 // - node is a source file - setBlockScopeContainer(node, /*cleanLocals*/ (symbolKind & SymbolFlags.HasLocals) === 0 && node.kind !== SyntaxKind.SourceFile); + setBlockScopeContainer(node, /*cleanLocals*/(symbolKind & SymbolFlags.HasLocals) === 0 && node.kind !== SyntaxKind.SourceFile); } forEachChild(node, bind); @@ -403,7 +423,7 @@ module ts { declareModuleMember(node, symbolKind, symbolExcludes); break; } - // fall through. + // fall through. default: if (!blockScopeContainer.locals) { blockScopeContainer.locals = {}; @@ -424,7 +444,7 @@ module ts { function bind(node: Node) { node.parent = parent; - + switch (node.kind) { case SyntaxKind.TypeParameter: bindDeclaration(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false); @@ -516,7 +536,7 @@ module ts { bindCatchVariableDeclaration(node); break; case SyntaxKind.ClassDeclaration: - bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); + bindBlockScopedDeclaration(node, SymbolFlags.Class, isAmbientContext(node) ? SymbolFlags.AmbientClassExcludes : SymbolFlags.ClassExcludes); break; case SyntaxKind.InterfaceDeclaration: bindDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c8d22b26728..807d8ce7564 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1340,7 +1340,8 @@ module ts { EnumMemberExcludes = Value, FunctionExcludes = Value & ~(Function | ValueModule), ClassExcludes = (Value | Type) & ~ValueModule, - InterfaceExcludes = Type & ~Interface, + AmbientClassExcludes = (Value | Type) & ~(ValueModule | Interface), + InterfaceExcludes = Type & ~(Interface | Class), RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),