mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Fix visibility checking of mutually recursive exports (#19929)
* Do visibility painting from collectLinkedAliases in checker to remove statefullness in declaration emit * Fix #17085 * Add deeply destructured array to test * Add test case for #18634 * Add PR feedback
This commit is contained in:
@@ -4047,15 +4047,15 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function collectLinkedAliases(node: Identifier): Node[] {
|
||||
function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined {
|
||||
let exportSymbol: Symbol;
|
||||
if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) {
|
||||
exportSymbol = resolveName(node.parent, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, Diagnostics.Cannot_find_name_0, node, /*isUse*/ false);
|
||||
exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false);
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ExportSpecifier) {
|
||||
exportSymbol = getTargetOfExportSpecifier(<ExportSpecifier>node.parent, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
|
||||
}
|
||||
const result: Node[] = [];
|
||||
let result: Node[];
|
||||
if (exportSymbol) {
|
||||
buildVisibleNodeList(exportSymbol.declarations);
|
||||
}
|
||||
@@ -4063,9 +4063,14 @@ namespace ts {
|
||||
|
||||
function buildVisibleNodeList(declarations: Declaration[]) {
|
||||
forEach(declarations, declaration => {
|
||||
getNodeLinks(declaration).isVisible = true;
|
||||
const resultNode = getAnyImportSyntax(declaration) || declaration;
|
||||
pushIfUnique(result, resultNode);
|
||||
if (setVisibility) {
|
||||
getNodeLinks(declaration).isVisible = true;
|
||||
}
|
||||
else {
|
||||
result = result || [];
|
||||
pushIfUnique(result, resultNode);
|
||||
}
|
||||
|
||||
if (isInternalModuleImportEqualsDeclaration(declaration)) {
|
||||
// Add the referenced top container visible
|
||||
@@ -23328,6 +23333,9 @@ namespace ts {
|
||||
|
||||
function checkExportSpecifier(node: ExportSpecifier) {
|
||||
checkAliasSymbol(node);
|
||||
if (compilerOptions.declaration) {
|
||||
collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); // Collect linked aliases to set visibility links
|
||||
}
|
||||
if (!(<ExportDeclaration>node.parent.parent).moduleSpecifier) {
|
||||
const exportedName = node.propertyName || node.name;
|
||||
// find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases)
|
||||
@@ -23365,6 +23373,10 @@ namespace ts {
|
||||
}
|
||||
if (node.expression.kind === SyntaxKind.Identifier) {
|
||||
markExportAsReferenced(node);
|
||||
|
||||
if (compilerOptions.declaration) {
|
||||
collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); // Sets visibility flags on refernced nodes
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkExpressionCached(node.expression);
|
||||
|
||||
@@ -1249,10 +1249,18 @@ namespace ts {
|
||||
writeLine();
|
||||
}
|
||||
|
||||
function bindingNameContainsVisibleBindingElement(node: BindingName): boolean {
|
||||
return !!node && isBindingPattern(node) && some(node.elements, elem => !isOmittedExpression(elem) && isVariableDeclarationVisible(elem));
|
||||
}
|
||||
|
||||
function isVariableDeclarationVisible(node: VariableDeclaration | BindingElement) {
|
||||
return resolver.isDeclarationVisible(node) || bindingNameContainsVisibleBindingElement(node.name);
|
||||
}
|
||||
|
||||
function emitVariableDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration) {
|
||||
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
|
||||
// so there is no check needed to see if declaration is visible
|
||||
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
|
||||
if (node.kind !== SyntaxKind.VariableDeclaration || isVariableDeclarationVisible(node)) {
|
||||
if (isBindingPattern(node.name)) {
|
||||
emitBindingPattern(<BindingPattern>node.name);
|
||||
}
|
||||
@@ -1324,14 +1332,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitBindingPattern(bindingPattern: BindingPattern) {
|
||||
// Only select non-omitted expression from the bindingPattern's elements.
|
||||
// Only select visible, non-omitted expression from the bindingPattern's elements.
|
||||
// We have to do this to avoid emitting trailing commas.
|
||||
// For example:
|
||||
// original: var [, c,,] = [ 2,3,4]
|
||||
// emitted: declare var c: number; // instead of declare var c:number, ;
|
||||
const elements: Node[] = [];
|
||||
for (const element of bindingPattern.elements) {
|
||||
if (element.kind !== SyntaxKind.OmittedExpression) {
|
||||
if (element.kind !== SyntaxKind.OmittedExpression && isVariableDeclarationVisible(element)) {
|
||||
elements.push(element);
|
||||
}
|
||||
}
|
||||
@@ -1371,7 +1379,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isVariableStatementVisible(node: VariableStatement) {
|
||||
return forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
|
||||
return forEach(node.declarationList.declarations, varDeclaration => isVariableDeclarationVisible(varDeclaration));
|
||||
}
|
||||
|
||||
function writeVariableStatement(node: VariableStatement) {
|
||||
@@ -1390,7 +1398,7 @@ namespace ts {
|
||||
else {
|
||||
write("var ");
|
||||
}
|
||||
emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible);
|
||||
emitCommaList(node.declarationList.declarations, emitVariableDeclaration, isVariableDeclarationVisible);
|
||||
write(";");
|
||||
writeLine();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user