From 960d114b6b746596d316bfef4f3d91e41110cd81 Mon Sep 17 00:00:00 2001
From: Wesley Wigham <wewigham@microsoft.com>
Date: Fri, 10 Nov 2017 13:39:42 -0800
Subject: [PATCH 1/5] Do visibility painting from collectLinkedAliases in
 checker to remove statefullness in declaration emit

---
 src/compiler/checker.ts                       | 17 ++++++++++----
 .../mutuallyRecursiveInterfaceDeclaration.js  | 23 +++++++++++++++++++
 ...uallyRecursiveInterfaceDeclaration.symbols | 20 ++++++++++++++++
 ...utuallyRecursiveInterfaceDeclaration.types | 20 ++++++++++++++++
 .../mutuallyRecursiveInterfaceDeclaration.ts  |  9 ++++++++
 5 files changed, 84 insertions(+), 5 deletions(-)
 create mode 100644 tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js
 create mode 100644 tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols
 create mode 100644 tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types
 create mode 100644 tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 999934e351c1a..281f0ec922cbc 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -4046,15 +4046,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);
             }
@@ -4062,9 +4062,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
@@ -23258,6 +23263,7 @@ namespace ts {
 
         function checkExportSpecifier(node: ExportSpecifier) {
             checkAliasSymbol(node);
+            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)
@@ -23295,6 +23301,7 @@ namespace ts {
             }
             if (node.expression.kind === SyntaxKind.Identifier) {
                 markExportAsReferenced(node);
+                collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); // Sets visibility flags on refernced nodes
             }
             else {
                 checkExpressionCached(node.expression);
diff --git a/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js
new file mode 100644
index 0000000000000..567cb71cafb5a
--- /dev/null
+++ b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js
@@ -0,0 +1,23 @@
+//// [mutuallyRecursiveInterfaceDeclaration.ts]
+interface A {
+    b: B
+}
+
+interface B {
+    a: A
+}
+export {A, B}
+
+//// [mutuallyRecursiveInterfaceDeclaration.js]
+"use strict";
+exports.__esModule = true;
+
+
+//// [mutuallyRecursiveInterfaceDeclaration.d.ts]
+interface A {
+    b: B;
+}
+interface B {
+    a: A;
+}
+export { A, B };
diff --git a/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols
new file mode 100644
index 0000000000000..b0ac456859c9b
--- /dev/null
+++ b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols
@@ -0,0 +1,20 @@
+=== tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts ===
+interface A {
+>A : Symbol(A, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 0, 0))
+
+    b: B
+>b : Symbol(A.b, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 0, 13))
+>B : Symbol(B, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 2, 1))
+}
+
+interface B {
+>B : Symbol(B, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 2, 1))
+
+    a: A
+>a : Symbol(B.a, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 4, 13))
+>A : Symbol(A, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 0, 0))
+}
+export {A, B}
+>A : Symbol(A, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 7, 8))
+>B : Symbol(B, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 7, 10))
+
diff --git a/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types
new file mode 100644
index 0000000000000..807687160b241
--- /dev/null
+++ b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types
@@ -0,0 +1,20 @@
+=== tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts ===
+interface A {
+>A : A
+
+    b: B
+>b : B
+>B : B
+}
+
+interface B {
+>B : B
+
+    a: A
+>a : A
+>A : A
+}
+export {A, B}
+>A : any
+>B : any
+
diff --git a/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts b/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts
new file mode 100644
index 0000000000000..e9609605c6925
--- /dev/null
+++ b/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts
@@ -0,0 +1,9 @@
+// @declaration: true
+interface A {
+    b: B
+}
+
+interface B {
+    a: A
+}
+export {A, B}
\ No newline at end of file

From c888ea3a8318a0a9cb325d1cf71ff4eee3ef42ba Mon Sep 17 00:00:00 2001
From: Wesley Wigham <wewigham@microsoft.com>
Date: Fri, 17 Nov 2017 13:54:57 -0800
Subject: [PATCH 2/5] Fix #17085

---
 src/compiler/declarationEmitter.ts            | 18 +++++---
 .../reference/destructuredDeclarationEmit.js  | 44 +++++++++++++++++++
 .../destructuredDeclarationEmit.symbols       | 36 +++++++++++++++
 .../destructuredDeclarationEmit.types         | 43 ++++++++++++++++++
 .../compiler/destructuredDeclarationEmit.ts   | 10 +++++
 5 files changed, 146 insertions(+), 5 deletions(-)
 create mode 100644 tests/baselines/reference/destructuredDeclarationEmit.js
 create mode 100644 tests/baselines/reference/destructuredDeclarationEmit.symbols
 create mode 100644 tests/baselines/reference/destructuredDeclarationEmit.types
 create mode 100644 tests/cases/compiler/destructuredDeclarationEmit.ts

diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
index ebd2985dd45c2..d629f6b450924 100644
--- a/src/compiler/declarationEmitter.ts
+++ b/src/compiler/declarationEmitter.ts
@@ -1249,10 +1249,18 @@ namespace ts {
             writeLine();
         }
 
+        function bindingNameContainsVisibleBindingElement(node: BindingName): boolean {
+            return !!node && isBindingPattern(node) && some(node.elements, elem => !isOmittedExpression(elem) && (resolver.isDeclarationVisible(elem) || bindingNameContainsVisibleBindingElement(elem.name)));
+        }
+
+        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();
         }
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.js b/tests/baselines/reference/destructuredDeclarationEmit.js
new file mode 100644
index 0000000000000..8ba01e7a7c1ef
--- /dev/null
+++ b/tests/baselines/reference/destructuredDeclarationEmit.js
@@ -0,0 +1,44 @@
+//// [tests/cases/compiler/destructuredDeclarationEmit.ts] ////
+
+//// [foo.ts]
+const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
+export { foo };
+//// [index.ts]
+import { foo } from './foo';
+export { foo };
+
+const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
+export { baz, ibaz };
+
+//// [foo.js]
+"use strict";
+exports.__esModule = true;
+var foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
+exports.foo = foo;
+//// [index.js]
+"use strict";
+exports.__esModule = true;
+var foo_1 = require("./foo");
+exports.foo = foo_1.foo;
+var baz = foo_1.foo.bar, bat = foo_1.foo.bat, _a = foo_1.foo.bam.bork, ibar = _a.bar, ibaz = _a.baz;
+exports.baz = baz;
+exports.ibaz = ibaz;
+
+
+//// [foo.d.ts]
+declare const foo: {
+    bar: string;
+    bat: string;
+    bam: {
+        bork: {
+            bar: string;
+            baz: string;
+        };
+    };
+};
+export { foo };
+//// [index.d.ts]
+import { foo } from './foo';
+export { foo };
+declare const baz: string, ibaz: string;
+export { baz, ibaz };
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.symbols b/tests/baselines/reference/destructuredDeclarationEmit.symbols
new file mode 100644
index 0000000000000..2ec953881666a
--- /dev/null
+++ b/tests/baselines/reference/destructuredDeclarationEmit.symbols
@@ -0,0 +1,36 @@
+=== tests/cases/compiler/foo.ts ===
+const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
+>foo : Symbol(foo, Decl(foo.ts, 0, 5))
+>bar : Symbol(bar, Decl(foo.ts, 0, 13))
+>bat : Symbol(bat, Decl(foo.ts, 0, 27))
+>bam : Symbol(bam, Decl(foo.ts, 0, 41))
+>bork : Symbol(bork, Decl(foo.ts, 0, 48))
+>bar : Symbol(bar, Decl(foo.ts, 0, 56))
+>baz : Symbol(baz, Decl(foo.ts, 0, 66))
+
+export { foo };
+>foo : Symbol(foo, Decl(foo.ts, 1, 8))
+
+=== tests/cases/compiler/index.ts ===
+import { foo } from './foo';
+>foo : Symbol(foo, Decl(index.ts, 0, 8))
+
+export { foo };
+>foo : Symbol(foo, Decl(index.ts, 1, 8))
+
+const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
+>bar : Symbol(bar, Decl(foo.ts, 0, 13))
+>baz : Symbol(baz, Decl(index.ts, 3, 7))
+>bat : Symbol(bat, Decl(index.ts, 3, 17))
+>bam : Symbol(bam, Decl(foo.ts, 0, 41))
+>bork : Symbol(bork, Decl(foo.ts, 0, 48))
+>bar : Symbol(bar, Decl(foo.ts, 0, 56))
+>ibar : Symbol(ibar, Decl(index.ts, 3, 37))
+>baz : Symbol(baz, Decl(foo.ts, 0, 66))
+>ibaz : Symbol(ibaz, Decl(index.ts, 3, 48))
+>foo : Symbol(foo, Decl(index.ts, 0, 8))
+
+export { baz, ibaz };
+>baz : Symbol(baz, Decl(index.ts, 4, 8))
+>ibaz : Symbol(ibaz, Decl(index.ts, 4, 13))
+
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.types b/tests/baselines/reference/destructuredDeclarationEmit.types
new file mode 100644
index 0000000000000..5f991d39dbf65
--- /dev/null
+++ b/tests/baselines/reference/destructuredDeclarationEmit.types
@@ -0,0 +1,43 @@
+=== tests/cases/compiler/foo.ts ===
+const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
+>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+>{ bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } } : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+>bar : string
+>'hello' : "hello"
+>bat : string
+>'world' : "world"
+>bam : { bork: { bar: string; baz: string; }; }
+>{ bork: { bar: 'a', baz: 'b' } } : { bork: { bar: string; baz: string; }; }
+>bork : { bar: string; baz: string; }
+>{ bar: 'a', baz: 'b' } : { bar: string; baz: string; }
+>bar : string
+>'a' : "a"
+>baz : string
+>'b' : "b"
+
+export { foo };
+>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+
+=== tests/cases/compiler/index.ts ===
+import { foo } from './foo';
+>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+
+export { foo };
+>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+
+const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
+>bar : any
+>baz : string
+>bat : string
+>bam : any
+>bork : any
+>bar : any
+>ibar : string
+>baz : any
+>ibaz : string
+>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+
+export { baz, ibaz };
+>baz : string
+>ibaz : string
+
diff --git a/tests/cases/compiler/destructuredDeclarationEmit.ts b/tests/cases/compiler/destructuredDeclarationEmit.ts
new file mode 100644
index 0000000000000..f7f9f67af14ec
--- /dev/null
+++ b/tests/cases/compiler/destructuredDeclarationEmit.ts
@@ -0,0 +1,10 @@
+// @declaration: true
+// @filename: foo.ts
+const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
+export { foo };
+// @filename: index.ts
+import { foo } from './foo';
+export { foo };
+
+const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
+export { baz, ibaz };
\ No newline at end of file

From 18962c1ed976ed74243989e401345a057c8f57bf Mon Sep 17 00:00:00 2001
From: Wesley Wigham <wewigham@microsoft.com>
Date: Fri, 17 Nov 2017 14:07:30 -0800
Subject: [PATCH 3/5] Add deeply destructured array to test

---
 .../reference/destructuredDeclarationEmit.js  | 32 ++++++++++---
 .../destructuredDeclarationEmit.symbols       | 29 ++++++++++--
 .../destructuredDeclarationEmit.types         | 45 +++++++++++++++++--
 .../compiler/destructuredDeclarationEmit.ts   | 12 +++--
 4 files changed, 100 insertions(+), 18 deletions(-)

diff --git a/tests/baselines/reference/destructuredDeclarationEmit.js b/tests/baselines/reference/destructuredDeclarationEmit.js
index 8ba01e7a7c1ef..4ae4cbfc35603 100644
--- a/tests/baselines/reference/destructuredDeclarationEmit.js
+++ b/tests/baselines/reference/destructuredDeclarationEmit.js
@@ -2,27 +2,38 @@
 
 //// [foo.ts]
 const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
-export { foo };
+const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]];
+export { foo, arr };
 //// [index.ts]
-import { foo } from './foo';
-export { foo };
+import { foo, arr } from './foo';
+export { foo, arr };
 
 const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
-export { baz, ibaz };
+export { baz, ibaz };
+
+const [ , one, , [, bee, , [, {sec} ]]] = arr;
+export { one, bee, sec };
 
 //// [foo.js]
 "use strict";
 exports.__esModule = true;
 var foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
 exports.foo = foo;
+var arr = [0, 1, 2, ['a', 'b', 'c', [{ def: 'def' }, { sec: 'sec' }]]];
+exports.arr = arr;
 //// [index.js]
 "use strict";
 exports.__esModule = true;
 var foo_1 = require("./foo");
 exports.foo = foo_1.foo;
+exports.arr = foo_1.arr;
 var baz = foo_1.foo.bar, bat = foo_1.foo.bat, _a = foo_1.foo.bam.bork, ibar = _a.bar, ibaz = _a.baz;
 exports.baz = baz;
 exports.ibaz = ibaz;
+var one = foo_1.arr[1], _b = foo_1.arr[3], bee = _b[1], _c = _b[3], sec = _c[1].sec;
+exports.one = one;
+exports.bee = bee;
+exports.sec = sec;
 
 
 //// [foo.d.ts]
@@ -36,9 +47,16 @@ declare const foo: {
         };
     };
 };
-export { foo };
+declare const arr: [0, 1, 2, ['a', 'b', 'c', [{
+    def: 'def';
+}, {
+    sec: 'sec';
+}]]];
+export { foo, arr };
 //// [index.d.ts]
-import { foo } from './foo';
-export { foo };
+import { foo, arr } from './foo';
+export { foo, arr };
 declare const baz: string, ibaz: string;
 export { baz, ibaz };
+declare const one: 1, bee: "b", sec: "sec";
+export { one, bee, sec };
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.symbols b/tests/baselines/reference/destructuredDeclarationEmit.symbols
index 2ec953881666a..0f823b46d5621 100644
--- a/tests/baselines/reference/destructuredDeclarationEmit.symbols
+++ b/tests/baselines/reference/destructuredDeclarationEmit.symbols
@@ -8,15 +8,25 @@ const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } }
 >bar : Symbol(bar, Decl(foo.ts, 0, 56))
 >baz : Symbol(baz, Decl(foo.ts, 0, 66))
 
-export { foo };
->foo : Symbol(foo, Decl(foo.ts, 1, 8))
+const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]];
+>arr : Symbol(arr, Decl(foo.ts, 1, 5))
+>def : Symbol(def, Decl(foo.ts, 1, 39))
+>sec : Symbol(sec, Decl(foo.ts, 1, 53))
+>def : Symbol(def, Decl(foo.ts, 1, 98))
+>sec : Symbol(sec, Decl(foo.ts, 1, 112))
+
+export { foo, arr };
+>foo : Symbol(foo, Decl(foo.ts, 2, 8))
+>arr : Symbol(arr, Decl(foo.ts, 2, 13))
 
 === tests/cases/compiler/index.ts ===
-import { foo } from './foo';
+import { foo, arr } from './foo';
 >foo : Symbol(foo, Decl(index.ts, 0, 8))
+>arr : Symbol(arr, Decl(index.ts, 0, 13))
 
-export { foo };
+export { foo, arr };
 >foo : Symbol(foo, Decl(index.ts, 1, 8))
+>arr : Symbol(arr, Decl(index.ts, 1, 13))
 
 const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
 >bar : Symbol(bar, Decl(foo.ts, 0, 13))
@@ -34,3 +44,14 @@ export { baz, ibaz };
 >baz : Symbol(baz, Decl(index.ts, 4, 8))
 >ibaz : Symbol(ibaz, Decl(index.ts, 4, 13))
 
+const [ , one, , [, bee, , [, {sec} ]]] = arr;
+>one : Symbol(one, Decl(index.ts, 6, 9))
+>bee : Symbol(bee, Decl(index.ts, 6, 19))
+>sec : Symbol(sec, Decl(index.ts, 6, 31))
+>arr : Symbol(arr, Decl(index.ts, 0, 13))
+
+export { one, bee, sec };
+>one : Symbol(one, Decl(index.ts, 7, 8))
+>bee : Symbol(bee, Decl(index.ts, 7, 13))
+>sec : Symbol(sec, Decl(index.ts, 7, 18))
+
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.types b/tests/baselines/reference/destructuredDeclarationEmit.types
index 5f991d39dbf65..b8e28e6bba300 100644
--- a/tests/baselines/reference/destructuredDeclarationEmit.types
+++ b/tests/baselines/reference/destructuredDeclarationEmit.types
@@ -15,15 +15,38 @@ const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } }
 >baz : string
 >'b' : "b"
 
-export { foo };
+const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]];
+>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]]
+>def : "def"
+>sec : "sec"
+>[0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]]
+>0 : 0
+>1 : 1
+>2 : 2
+>['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]] : ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]
+>'a' : "a"
+>'b' : "b"
+>'c' : "c"
+>[{def: 'def'}, {sec: 'sec'}] : [{ def: "def"; }, { sec: "sec"; }]
+>{def: 'def'} : { def: "def"; }
+>def : string
+>'def' : "def"
+>{sec: 'sec'} : { sec: "sec"; }
+>sec : string
+>'sec' : "sec"
+
+export { foo, arr };
 >foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]]
 
 === tests/cases/compiler/index.ts ===
-import { foo } from './foo';
+import { foo, arr } from './foo';
 >foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]]
 
-export { foo };
+export { foo, arr };
 >foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; }
+>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]]
 
 const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
 >bar : any
@@ -41,3 +64,19 @@ export { baz, ibaz };
 >baz : string
 >ibaz : string
 
+const [ , one, , [, bee, , [, {sec} ]]] = arr;
+> : undefined
+>one : 1
+> : undefined
+> : undefined
+>bee : "b"
+> : undefined
+> : undefined
+>sec : "sec"
+>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]]
+
+export { one, bee, sec };
+>one : 1
+>bee : "b"
+>sec : "sec"
+
diff --git a/tests/cases/compiler/destructuredDeclarationEmit.ts b/tests/cases/compiler/destructuredDeclarationEmit.ts
index f7f9f67af14ec..73f86f468ea0e 100644
--- a/tests/cases/compiler/destructuredDeclarationEmit.ts
+++ b/tests/cases/compiler/destructuredDeclarationEmit.ts
@@ -1,10 +1,14 @@
 // @declaration: true
 // @filename: foo.ts
 const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } };
-export { foo };
+const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]];
+export { foo, arr };
 // @filename: index.ts
-import { foo } from './foo';
-export { foo };
+import { foo, arr } from './foo';
+export { foo, arr };
 
 const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
-export { baz, ibaz };
\ No newline at end of file
+export { baz, ibaz };
+
+const [ , one, , [, bee, , [, {sec} ]]] = arr;
+export { one, bee, sec };
\ No newline at end of file

From 4c1f9cb38f50278bb3137c28718a771bafbfa29b Mon Sep 17 00:00:00 2001
From: Wesley Wigham <wewigham@microsoft.com>
Date: Fri, 17 Nov 2017 14:11:14 -0800
Subject: [PATCH 4/5] Add test case for #18634

---
 .../reference/destructuredDeclarationEmit.js  | 17 ++++++++++++++-
 .../destructuredDeclarationEmit.symbols       | 16 ++++++++++++++
 .../destructuredDeclarationEmit.types         | 21 +++++++++++++++++++
 .../compiler/destructuredDeclarationEmit.ts   |  9 +++++++-
 4 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/tests/baselines/reference/destructuredDeclarationEmit.js b/tests/baselines/reference/destructuredDeclarationEmit.js
index 4ae4cbfc35603..d41976525819e 100644
--- a/tests/baselines/reference/destructuredDeclarationEmit.js
+++ b/tests/baselines/reference/destructuredDeclarationEmit.js
@@ -12,7 +12,15 @@ const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
 export { baz, ibaz };
 
 const [ , one, , [, bee, , [, {sec} ]]] = arr;
-export { one, bee, sec };
+export { one, bee, sec };
+
+const getFoo = () => ({
+    foo: 'foo'
+});
+
+const { foo: foo2 } = getFoo();
+export { foo2 };
+
 
 //// [foo.js]
 "use strict";
@@ -34,6 +42,11 @@ var one = foo_1.arr[1], _b = foo_1.arr[3], bee = _b[1], _c = _b[3], sec = _c[1].
 exports.one = one;
 exports.bee = bee;
 exports.sec = sec;
+var getFoo = function () { return ({
+    foo: 'foo'
+}); };
+var foo2 = getFoo().foo;
+exports.foo2 = foo2;
 
 
 //// [foo.d.ts]
@@ -60,3 +73,5 @@ declare const baz: string, ibaz: string;
 export { baz, ibaz };
 declare const one: 1, bee: "b", sec: "sec";
 export { one, bee, sec };
+declare const foo2: string;
+export { foo2 };
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.symbols b/tests/baselines/reference/destructuredDeclarationEmit.symbols
index 0f823b46d5621..daeed5befd71b 100644
--- a/tests/baselines/reference/destructuredDeclarationEmit.symbols
+++ b/tests/baselines/reference/destructuredDeclarationEmit.symbols
@@ -55,3 +55,19 @@ export { one, bee, sec };
 >bee : Symbol(bee, Decl(index.ts, 7, 13))
 >sec : Symbol(sec, Decl(index.ts, 7, 18))
 
+const getFoo = () => ({
+>getFoo : Symbol(getFoo, Decl(index.ts, 9, 5))
+
+    foo: 'foo'
+>foo : Symbol(foo, Decl(index.ts, 9, 23))
+
+});
+
+const { foo: foo2 } = getFoo();
+>foo : Symbol(foo, Decl(index.ts, 9, 23))
+>foo2 : Symbol(foo2, Decl(index.ts, 13, 7))
+>getFoo : Symbol(getFoo, Decl(index.ts, 9, 5))
+
+export { foo2 };
+>foo2 : Symbol(foo2, Decl(index.ts, 14, 8))
+
diff --git a/tests/baselines/reference/destructuredDeclarationEmit.types b/tests/baselines/reference/destructuredDeclarationEmit.types
index b8e28e6bba300..94845f94885be 100644
--- a/tests/baselines/reference/destructuredDeclarationEmit.types
+++ b/tests/baselines/reference/destructuredDeclarationEmit.types
@@ -80,3 +80,24 @@ export { one, bee, sec };
 >bee : "b"
 >sec : "sec"
 
+const getFoo = () => ({
+>getFoo : () => { foo: string; }
+>() => ({    foo: 'foo'}) : () => { foo: string; }
+>({    foo: 'foo'}) : { foo: string; }
+>{    foo: 'foo'} : { foo: string; }
+
+    foo: 'foo'
+>foo : string
+>'foo' : "foo"
+
+});
+
+const { foo: foo2 } = getFoo();
+>foo : any
+>foo2 : string
+>getFoo() : { foo: string; }
+>getFoo : () => { foo: string; }
+
+export { foo2 };
+>foo2 : string
+
diff --git a/tests/cases/compiler/destructuredDeclarationEmit.ts b/tests/cases/compiler/destructuredDeclarationEmit.ts
index 73f86f468ea0e..99435aff5b1ad 100644
--- a/tests/cases/compiler/destructuredDeclarationEmit.ts
+++ b/tests/cases/compiler/destructuredDeclarationEmit.ts
@@ -11,4 +11,11 @@ const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo;
 export { baz, ibaz };
 
 const [ , one, , [, bee, , [, {sec} ]]] = arr;
-export { one, bee, sec };
\ No newline at end of file
+export { one, bee, sec };
+
+const getFoo = () => ({
+    foo: 'foo'
+});
+
+const { foo: foo2 } = getFoo();
+export { foo2 };

From ea41813731de614f93c6cf0b1af520aee4d2aa8c Mon Sep 17 00:00:00 2001
From: Wesley Wigham <wewigham@microsoft.com>
Date: Tue, 21 Nov 2017 14:09:59 -0800
Subject: [PATCH 5/5] Add PR feedback

---
 src/compiler/checker.ts            | 9 +++++++--
 src/compiler/declarationEmitter.ts | 2 +-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 281f0ec922cbc..4a8dce1846e5a 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -23263,7 +23263,9 @@ namespace ts {
 
         function checkExportSpecifier(node: ExportSpecifier) {
             checkAliasSymbol(node);
-            collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); // Collect linked aliases to set visibility links
+            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)
@@ -23301,7 +23303,10 @@ namespace ts {
             }
             if (node.expression.kind === SyntaxKind.Identifier) {
                 markExportAsReferenced(node);
-                collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); // Sets visibility flags on refernced nodes
+
+                if (compilerOptions.declaration) {
+                    collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); // Sets visibility flags on refernced nodes
+                }
             }
             else {
                 checkExpressionCached(node.expression);
diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
index d629f6b450924..dc76e0ddf5028 100644
--- a/src/compiler/declarationEmitter.ts
+++ b/src/compiler/declarationEmitter.ts
@@ -1250,7 +1250,7 @@ namespace ts {
         }
 
         function bindingNameContainsVisibleBindingElement(node: BindingName): boolean {
-            return !!node && isBindingPattern(node) && some(node.elements, elem => !isOmittedExpression(elem) && (resolver.isDeclarationVisible(elem) || bindingNameContainsVisibleBindingElement(elem.name)));
+            return !!node && isBindingPattern(node) && some(node.elements, elem => !isOmittedExpression(elem) && isVariableDeclarationVisible(elem));
         }
 
         function isVariableDeclarationVisible(node: VariableDeclaration | BindingElement) {