Add constructor functions to aliasable expressions (#36108)

* Add constructor functions to aliasable expressions

Fixes #35228, at least the crash. There are still a couple of errors
that are probably incorrect.

Note that isJSConstructor relies on parent pointers and the ability to
merge symbols, so I had to move isAliasSymbolDeclaration (back?) to the
checker.

* add simple test case

* remove errors in test

* fix bad merge
This commit is contained in:
Nathan Shively-Sanders
2020-01-29 09:36:59 -08:00
committed by GitHub
parent 49282d9fba
commit 0cf100dcf8
11 changed files with 294 additions and 30 deletions

View File

@@ -2181,6 +2181,43 @@ namespace ts {
return find<Declaration>(symbol.declarations, isAliasSymbolDeclaration);
}
/**
* An alias symbol is created by one of the following declarations:
* import <symbol> = ...
* import <symbol> from ...
* import * as <symbol> from ...
* import { x as <symbol> } from ...
* export { x as <symbol> } from ...
* export * as ns <symbol> from ...
* export = <EntityNameExpression>
* export default <EntityNameExpression>
* module.exports = <EntityNameExpression>
* {<Identifier>}
* {name: <EntityNameExpression>}
*/
function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.NamespaceExport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node) ||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) ||
isPropertyAccessExpression(node)
&& isBinaryExpression(node.parent)
&& node.parent.left === node
&& node.parent.operatorToken.kind === SyntaxKind.EqualsToken
&& isAliasableOrJsExpression(node.parent.right) ||
node.kind === SyntaxKind.ShorthandPropertyAssignment ||
node.kind === SyntaxKind.PropertyAssignment && isAliasableOrJsExpression((node as PropertyAssignment).initializer);
}
function isAliasableOrJsExpression(e: Expression) {
return isAliasableExpression(e) || isFunctionExpression(e) && isJSConstructor(e);
}
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration, dontResolveAlias: boolean): Symbol | undefined {
if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)));
@@ -5784,8 +5821,8 @@ namespace ts {
function serializeAsAlias(symbol: Symbol, localName: string, modifierFlags: ModifierFlags) {
// synthesize an alias, eg `export { symbolName as Name }`
// need to mark the alias `symbol` points
// at as something we need to serialize as a private declaration as well
// need to mark the alias `symbol` points at
// as something we need to serialize as a private declaration as well
const node = getDeclarationOfAliasSymbol(symbol);
if (!node) return Debug.fail();
const target = getMergedSymbol(getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true));

View File

@@ -2738,33 +2738,6 @@ namespace ts {
return false;
}
// An alias symbol is created by one of the following declarations:
// import <symbol> = ...
// import <symbol> from ...
// import * as <symbol> from ...
// import { x as <symbol> } from ...
// export { x as <symbol> } from ...
// export * as ns <symbol> from ...
// export = <EntityNameExpression>
// export default <EntityNameExpression>
// module.exports = <EntityNameExpression>
// {<Identifier>}
// {name: <EntityNameExpression>}
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.NamespaceExport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node) ||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) ||
isPropertyAccessExpression(node) && isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAliasableExpression(node.parent.right) ||
node.kind === SyntaxKind.ShorthandPropertyAssignment ||
node.kind === SyntaxKind.PropertyAssignment && isAliasableExpression((node as PropertyAssignment).initializer);
}
export function getTypeOnlyCompatibleAliasDeclarationFromName(node: Identifier): TypeOnlyCompatibleAliasDeclaration | undefined {
switch (node.parent.kind) {
case SyntaxKind.ImportClause:
@@ -2775,7 +2748,7 @@ namespace ts {
}
}
function isAliasableExpression(e: Expression) {
export function isAliasableExpression(e: Expression) {
return isEntityNameExpression(e) || isClassExpression(e);
}