diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 3523cdb05ee..e59ddfd7317 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -17,9 +17,7 @@ namespace ts { ? new ConstructorForKind(kind, location.pos, location.end) : new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1); - if (flags) { - node.flags = flags; - } + node.flags = flags | NodeFlags.Synthesized; return node; } @@ -68,8 +66,7 @@ namespace ts { // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of // the original node. We also need to exclude specific properties and only include own- // properties (to skip members already defined on the shared prototype). - const clone = createNode(node.kind, /*location*/ undefined, /*flags*/ undefined); - clone.flags = node.flags; + const clone = createNode(node.kind, /*location*/ undefined, node.flags); clone.original = node; for (const key in node) { @@ -827,6 +824,7 @@ namespace ts { // Create an identifier and give it a parent. This allows us to resolve the react // namespace during emit. const react = createIdentifier(reactNamespace || "React"); + react.flags &= ~NodeFlags.Synthesized; react.parent = parent; return react; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7689055c746..d9d1eee73d4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2034,7 +2034,7 @@ namespace ts { // FormalParameter [Yield,Await]: // BindingElement[?Yield,?Await] node.name = parseIdentifierOrPattern(); - if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifierKind(token)) { + if (getFullWidth(node.name) === 0 && !hasModifiers(node) && isModifierKind(token)) { // in cases like // 'use strict' // function foo(static) diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 9d3ed9f051c..3b7cf95d2f1 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1752,7 +1752,10 @@ namespace ts { function serializeEntityNameAsExpression(node: EntityName, useFallback: boolean): Expression { switch (node.kind) { case SyntaxKind.Identifier: + // Create a clone of the name with a new parent, and treat it as if it were + // a source tree node for the purposes of the checker. const name = getMutableClone(node); + name.flags &= ~NodeFlags.Synthesized; name.original = undefined; name.parent = currentScope; if (useFallback) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 059434e5251..42beb0e6335 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -383,6 +383,7 @@ namespace ts { Let = 1 << 0, // Variable declaration Const = 1 << 1, // Variable declaration NestedNamespace = 1 << 2, // Namespace declaration + Synthesized = 1 << 3, // Node was synthesized during transformation Namespace = 1 << 12, // Namespace declaration ExportContext = 1 << 13, // Export context (initialized by binding) ContainsThis = 1 << 14, // Interface contains references to "this" diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5f023b3909f..655f731f10c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1831,14 +1831,17 @@ namespace ts { } export function isSourceTreeNode(node: Node): boolean { - return node.original === undefined - && (node.parent !== undefined || node.kind === SyntaxKind.SourceFile); + return (node.flags & NodeFlags.Synthesized) === 0; } export function getSourceTreeNode(node: Node): Node { + if (isSourceTreeNode(node)) { + return node; + } + node = getOriginalNode(node); - if (node && (node.parent !== undefined || node.kind === SyntaxKind.SourceFile)) { + if (isSourceTreeNode(node)) { return node; }