diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7094f9e7ea8..9dabafb0cde 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10718,7 +10718,7 @@ module ts { } function getBlockScopedVariableId(n: Identifier): number { - Debug.assert(n.parent !== undefined); + Debug.assert(!nodeIsSynthesized(n)); // ignore name parts of property access expressions if (n.parent.kind === SyntaxKind.PropertyAccessExpression && @@ -10736,8 +10736,14 @@ module ts { var symbol = declarationSymbol || getNodeLinks(n).resolvedSymbol || resolveName(n, n.text, SymbolFlags.BlockScopedVariable | SymbolFlags.Import, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); - - return symbol && symbol.flags & SymbolFlags.BlockScopedVariable ? symbol.id : undefined; + + if (symbol && (symbol.flags & SymbolFlags.BlockScopedVariable)) { + // side-effect of calling this method: + // assign id to symbol if it was not yet set + getSymbolLinks(symbol); + return symbol.id; + } + return undefined; } function createResolver(): EmitResolver { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 1cec38872af..fbe341ccd28 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -32,7 +32,7 @@ module ts { leadingCommentRanges?: CommentRange[]; trailingCommentRanges?: CommentRange[]; } - + interface ScopeFrame { names: Map; previous: ScopeFrame; @@ -2100,7 +2100,7 @@ module ts { name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0 : 1) + CharacterCodes.a) : tempCount - 25); tempCount++; } - var result = createNode(SyntaxKind.Identifier); + var result = createSynthesizedNode(SyntaxKind.Identifier); result.text = name; return result; } @@ -2647,14 +2647,6 @@ module ts { } } - function createSynthesizedNode(kind: SyntaxKind): Node { - var node = createNode(kind); - node.pos = -1; - node.end = -1; - - return node; - } - function emitDownlevelObjectLiteralWithComputedProperties(node: ObjectLiteralExpression, firstComputedPropertyIndex: number): void { var parenthesizedObjectLiteral = createDownlevelObjectLiteralWithComputedProperties(node, firstComputedPropertyIndex); return emit(parenthesizedObjectLiteral); @@ -3551,9 +3543,9 @@ module ts { } function createVoidZero(): Expression { - var zero = createNode(SyntaxKind.NumericLiteral); + var zero = createSynthesizedNode(SyntaxKind.NumericLiteral); zero.text = "0"; - var result = createNode(SyntaxKind.VoidExpression); + var result = createSynthesizedNode(SyntaxKind.VoidExpression); result.expression = zero; return result; } @@ -3619,11 +3611,11 @@ module ts { // we need to generate a temporary variable value = ensureIdentifier(value); // Return the expression 'value === void 0 ? defaultValue : value' - var equals = createNode(SyntaxKind.BinaryExpression); + var equals = createSynthesizedNode(SyntaxKind.BinaryExpression); equals.left = value; - equals.operatorToken = createNode(SyntaxKind.EqualsEqualsEqualsToken); + equals.operatorToken = createSynthesizedNode(SyntaxKind.EqualsEqualsEqualsToken); equals.right = createVoidZero(); - var cond = createNode(SyntaxKind.ConditionalExpression); + var cond = createSynthesizedNode(SyntaxKind.ConditionalExpression); cond.condition = equals; cond.whenTrue = defaultValue; cond.whenFalse = value; @@ -3631,7 +3623,7 @@ module ts { } function createNumericLiteral(value: number) { - var node = createNode(SyntaxKind.NumericLiteral); + var node = createSynthesizedNode(SyntaxKind.NumericLiteral); node.text = "" + value; return node; } @@ -3640,7 +3632,7 @@ module ts { if (expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) { return expr; } - var node = createNode(SyntaxKind.ParenthesizedExpression); + var node = createSynthesizedNode(SyntaxKind.ParenthesizedExpression); node.expression = expr; return node; } @@ -3649,14 +3641,14 @@ module ts { if (propName.kind !== SyntaxKind.Identifier) { return createElementAccess(object, propName); } - var node = createNode(SyntaxKind.PropertyAccessExpression); + var node = createSynthesizedNode(SyntaxKind.PropertyAccessExpression); node.expression = parenthesizeForAccess(object); node.name = propName; return node; } function createElementAccess(object: Expression, index: Expression): Expression { - var node = createNode(SyntaxKind.ElementAccessExpression); + var node = createSynthesizedNode(SyntaxKind.ElementAccessExpression); node.expression = parenthesizeForAccess(object); node.argumentExpression = index; return node; @@ -3843,6 +3835,7 @@ module ts { case SyntaxKind.CatchClause: case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: case SyntaxKind.SwitchKeyword: return current; case SyntaxKind.Block: @@ -3872,12 +3865,12 @@ module ts { function renameNonTopLevelLetAndConst(node: Node): void { // do not rename if // - language version is ES6+ - // - node is synthesized (does not have a parent) + // - node is synthesized // - node is not identifier (can happen when tree is malformed) // - node is definitely not name of variable declaration. // it still can be part of parameter declaration, this check will be done next if (languageVersion >= ScriptTarget.ES6 || - !node.parent || + nodeIsSynthesized(node) || node.kind !== SyntaxKind.Identifier || (node.parent.kind !== SyntaxKind.VariableDeclaration && node.parent.kind !== SyntaxKind.BindingElement)) { return; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 437894d9cfc..50a8de9671d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1117,6 +1117,20 @@ module ts { return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN); } + // @internal + export function nodeIsSynthesized(node: Node): boolean { + return node.pos === -1 && node.end === -1; + } + + // @internal + export function createSynthesizedNode(kind: SyntaxKind): Node { + var node = createNode(kind); + node.pos = -1; + node.end = -1; + + return node; + } + // @internal export function generateUniqueName(baseName: string, isExistingName: (name: string) => boolean): string { // First try '_name'