From 2e8e4a1f5c22cc5514a0a2137217b6037cde4779 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 20 Apr 2015 02:24:47 -0700 Subject: [PATCH] Add clarifying comments to the binder. --- src/compiler/binder.ts | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6f8140a983a..e27851c7806 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -143,7 +143,7 @@ module ts { return node.name ? declarationNameToString(node.name) : getDeclarationName(node); } - function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { + function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { Debug.assert(!hasDynamicName(node)); // The exported symbol for an export default function/class node is always named "default" @@ -151,7 +151,27 @@ module ts { let symbol: Symbol; if (name !== undefined) { - symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(SymbolFlags.None, name)); + // Check and see if the symbol table already has a symbol with this name. If not, + // create a new symbol with this name and add it to the table. Note that we don't + // give the new symbol any flags *yet*. This ensures that it will not conflict + // witht he 'excludes' flags we pass in. + // + // If we do get an existing symbol, see if it conflicts with the new symbol we're + // creating. For example, a 'var' symbol and a 'class' symbol will conflict within + // the same symbol table. If we have a conflict, report the issue on each + // declaration we have for this symbol, and then create a new symbol for this + // declaration. + // + // If we created a new symbol, either because we didn't have a symbol with this name + // in the symbol table, or we conflicted with an existing symbol, then just add this + // node as the sole declaration of the new symbol. + // + // Otherwise, we'll be merging into a compatible existing symbol (for example when + // you have multiple 'vars' with the same name in the same container). In this case + // just add this node into the declarations list of the symbol. + symbol = hasProperty(symbolTable, name) + ? symbolTable[name] + : (symbolTable[name] = createSymbol(SymbolFlags.None, name)); if (symbol.flags & excludes) { if (node.name) { node.name.parent = node; @@ -160,9 +180,8 @@ module ts { // 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 => { file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration))); }); @@ -204,7 +223,8 @@ module ts { // but return the export symbol (by calling getExportSymbolOfValueSymbolIfExported). That way // when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope. if (hasExportModifier || container.flags & NodeFlags.ExportContext) { - let exportKind = (symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) | + let exportKind = + (symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) | (symbolFlags & SymbolFlags.Type ? SymbolFlags.ExportType : 0) | (symbolFlags & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0); let local = declareSymbol(container.locals, undefined, node, exportKind, symbolExcludes); @@ -541,11 +561,10 @@ module ts { // do not treat function block a block-scope container // all block-scope locals that reside in this block should go to the function locals. // Otherwise this won't be considered as redeclaration of a block scoped local: - // function foo() { - // let x; + // function foo(x) { // let x; // } - // 'let x' will be placed into the function locals and 'let x' - into the locals of the block + // 'x' will be placed into the function locals and 'let x' - into the locals of the block return isFunctionLike(node.parent) ? SymbolFlags.None : SymbolFlags.BlockScopedContainer; case SyntaxKind.CatchClause: case SyntaxKind.ForStatement: