Fix bug: Ensure export = symbol always has a valueDeclaration (#26973)

This commit is contained in:
Andy 2018-09-13 12:53:46 -07:00 committed by GitHub
parent cc7bfc0349
commit 1a69f78fba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 24 deletions

View file

@ -234,13 +234,17 @@ namespace ts {
}
if (symbolFlags & SymbolFlags.Value) {
const { valueDeclaration } = symbol;
if (!valueDeclaration ||
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
// other kinds of value declarations take precedence over modules and assignment declarations
symbol.valueDeclaration = node;
}
setValueDeclaration(symbol, node);
}
}
function setValueDeclaration(symbol: Symbol, node: Declaration): void {
const { valueDeclaration } = symbol;
if (!valueDeclaration ||
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
// other kinds of value declarations take precedence over modules and assignment declarations
symbol.valueDeclaration = node;
}
}
@ -2286,14 +2290,19 @@ namespace ts {
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)!);
}
else {
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node)
const flags = exportAssignmentIsAlias(node)
// An export default clause with an EntityNameExpression or a class expression exports all meanings of that identifier or expression;
? SymbolFlags.Alias
// An export default clause with any other expression exports a value
: SymbolFlags.Property;
// If there is an `export default x;` alias declaration, can't `export default` anything else.
// (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
const symbol = declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
if (node.isExportEquals) {
// Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set.
setValueDeclaration(symbol, node);
}
}
}

View file

@ -1,9 +1,10 @@
tests/cases/compiler/errorForConflictingExportEqualsValue.ts(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements.
/a.ts(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements.
==== tests/cases/compiler/errorForConflictingExportEqualsValue.ts (1 errors) ====
==== /a.ts (1 errors) ====
export var x;
export = {};
~~~~~~~~~~~~
export = x;
~~~~~~~~~~~
!!! error TS2309: An export assignment cannot be used in a module with other exported elements.
import("./a");

View file

@ -1,8 +1,10 @@
//// [errorForConflictingExportEqualsValue.ts]
//// [a.ts]
export var x;
export = {};
export = x;
import("./a");
//// [errorForConflictingExportEqualsValue.js]
//// [a.js]
"use strict";
module.exports = {};
Promise.resolve().then(function () { return require("./a"); });
module.exports = exports.x;

View file

@ -1,6 +1,10 @@
=== tests/cases/compiler/errorForConflictingExportEqualsValue.ts ===
=== /a.ts ===
export var x;
>x : Symbol(x, Decl(errorForConflictingExportEqualsValue.ts, 0, 10))
>x : Symbol(x, Decl(a.ts, 0, 10))
export = {};
export = x;
>x : Symbol(x, Decl(a.ts, 0, 10))
import("./a");
>"./a" : Symbol("/a", Decl(a.ts, 0, 0))

View file

@ -1,7 +1,11 @@
=== tests/cases/compiler/errorForConflictingExportEqualsValue.ts ===
=== /a.ts ===
export var x;
>x : any
export = {};
>{} : {}
export = x;
>x : any
import("./a");
>import("./a") : Promise<typeof import("/a").x>
>"./a" : "./a"

View file

@ -1,2 +1,5 @@
// @lib: es6
// @Filename: /a.ts
export var x;
export = {};
export = x;
import("./a");