Improve valueDeclaration for js module merges (#24707)

Nearly everything in a merge of JS special assignments looks like a
valueDeclaration. This commit ensures that intermediate "module
declarations" are not used when a better valueDeclaration is available:

```js
// File1.js
var X = {}
X.Y.Z = class { }

// File2.js
X.Y = {}
```

In the above example, the `Y` in `X.Y.Z = class { }` was used as the
valueDeclaration for `Y` because it appeared before `X.Y = {}` in the
compilation.

This change exposed a bug in binding, #24703, that required a change in
typeFromPropertyAssignmentOutOfOrder. The test still fails for the
original reason it was created, and the new bug #24703 contains a repro.
This commit is contained in:
Nathan Shively-Sanders
2018-06-06 11:11:15 -07:00
committed by GitHub
parent 942c42bf29
commit 30994c86e4
9 changed files with 180 additions and 40 deletions
+1 -1
View File
@@ -236,7 +236,7 @@ namespace ts {
if (symbolFlags & SymbolFlags.Value) {
const { valueDeclaration } = symbol;
if (!valueDeclaration ||
(valueDeclaration.kind !== node.kind && valueDeclaration.kind === SyntaxKind.ModuleDeclaration)) {
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
// other kinds of value declarations take precedence over modules
symbol.valueDeclaration = node;
}
+1 -1
View File
@@ -921,7 +921,7 @@ namespace ts {
target.flags |= source.flags;
if (source.valueDeclaration &&
(!target.valueDeclaration ||
(target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) {
isEffectiveModuleDeclaration(target.valueDeclaration) && !isEffectiveModuleDeclaration(source.valueDeclaration))) {
// other kinds of value declarations take precedence over modules
target.valueDeclaration = source.valueDeclaration;
}
+10
View File
@@ -451,6 +451,16 @@ namespace ts {
return isModuleDeclaration(node) && isStringLiteral(node.name);
}
/**
* An effective module (namespace) declaration is either
* 1. An actual declaration: namespace X { ... }
* 2. A Javascript declaration, which is:
* An identifier in a nested property access expression: Y in `X.Y.Z = { ... }`
*/
export function isEffectiveModuleDeclaration(node: Node) {
return isModuleDeclaration(node) || isIdentifier(node);
}
/** Given a symbol for a module, checks that it is a shorthand ambient module. */
export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean {
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);