Skip to content

Commit 6b25dab

Browse files
authored
Merge pull request #10798 from Microsoft/fix10778
Fix deferred export of array binding pattern
2 parents e16cf96 + c048f7c commit 6b25dab

18 files changed

+114
-37
lines changed

src/compiler/binder.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1150,8 +1150,8 @@ namespace ts {
11501150
currentFlow = finishFlowLabel(postExpressionLabel);
11511151
}
11521152

1153-
function bindInitializedVariableFlow(node: VariableDeclaration | BindingElement) {
1154-
const name = node.name;
1153+
function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
1154+
const name = !isOmittedExpression(node) ? node.name : undefined;
11551155
if (isBindingPattern(name)) {
11561156
for (const child of name.elements) {
11571157
bindInitializedVariableFlow(child);

src/compiler/checker.ts

+16-10
Original file line numberDiff line numberDiff line change
@@ -2505,8 +2505,8 @@ namespace ts {
25052505
}
25062506
}
25072507

2508-
function buildBindingElementDisplay(bindingElement: BindingElement, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
2509-
if (bindingElement.kind === SyntaxKind.OmittedExpression) {
2508+
function buildBindingElementDisplay(bindingElement: ArrayBindingElement, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
2509+
if (isOmittedExpression(bindingElement)) {
25102510
return;
25112511
}
25122512
Debug.assert(bindingElement.kind === SyntaxKind.BindingElement);
@@ -3125,7 +3125,7 @@ namespace ts {
31253125
}
31263126

31273127
// Return the type implied by an object binding pattern
3128-
function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
3128+
function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
31293129
const members = createMap<Symbol>();
31303130
let hasComputedProperties = false;
31313131
forEach(pattern.elements, e => {
@@ -3156,11 +3156,12 @@ namespace ts {
31563156
// Return the type implied by an array binding pattern
31573157
function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
31583158
const elements = pattern.elements;
3159-
if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) {
3159+
const lastElement = lastOrUndefined(elements);
3160+
if (elements.length === 0 || (!isOmittedExpression(lastElement) && lastElement.dotDotDotToken)) {
31603161
return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType;
31613162
}
31623163
// If the pattern has at least one element, and no rest element, then it should imply a tuple type.
3163-
const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
3164+
const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
31643165
let result = createTupleType(elementTypes);
31653166
if (includePatternInType) {
31663167
result = cloneTypeReference(result);
@@ -3178,8 +3179,8 @@ namespace ts {
31783179
// the parameter.
31793180
function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean, reportErrors?: boolean): Type {
31803181
return pattern.kind === SyntaxKind.ObjectBindingPattern
3181-
? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors)
3182-
: getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors);
3182+
? getTypeFromObjectBindingPattern(<ObjectBindingPattern>pattern, includePatternInType, reportErrors)
3183+
: getTypeFromArrayBindingPattern(<ArrayBindingPattern>pattern, includePatternInType, reportErrors);
31833184
}
31843185

31853186
// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
@@ -12413,7 +12414,7 @@ namespace ts {
1241312414
function assignBindingElementTypes(node: VariableLikeDeclaration) {
1241412415
if (isBindingPattern(node.name)) {
1241512416
for (const element of (<BindingPattern>node.name).elements) {
12416-
if (element.kind !== SyntaxKind.OmittedExpression) {
12417+
if (!isOmittedExpression(element)) {
1241712418
if (element.name.kind === SyntaxKind.Identifier) {
1241812419
getSymbolLinks(getSymbolOfNode(element)).type = getTypeForBindingElement(element);
1241912420
}
@@ -13889,7 +13890,12 @@ namespace ts {
1388913890
pattern: BindingPattern,
1389013891
predicateVariableNode: Node,
1389113892
predicateVariableName: string) {
13892-
for (const { name } of pattern.elements) {
13893+
for (const element of pattern.elements) {
13894+
if (isOmittedExpression(element)) {
13895+
continue;
13896+
}
13897+
13898+
const name = element.name;
1389313899
if (name.kind === SyntaxKind.Identifier &&
1389413900
(<Identifier>name).text === predicateVariableName) {
1389513901
error(predicateVariableNode,
@@ -19999,7 +20005,7 @@ namespace ts {
1999920005
else {
2000020006
const elements = (<BindingPattern>name).elements;
2000120007
for (const element of elements) {
20002-
if (element.kind !== SyntaxKind.OmittedExpression) {
20008+
if (!isOmittedExpression(element)) {
2000320009
checkGrammarNameInLetOrConstDeclarations(element.name);
2000420010
}
2000520011
}

src/compiler/emitter.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,9 @@ const _super = (function (geti, seti) {
554554

555555
// Binding patterns
556556
case SyntaxKind.ObjectBindingPattern:
557-
return emitObjectBindingPattern(<BindingPattern>node);
557+
return emitObjectBindingPattern(<ObjectBindingPattern>node);
558558
case SyntaxKind.ArrayBindingPattern:
559-
return emitArrayBindingPattern(<BindingPattern>node);
559+
return emitArrayBindingPattern(<ArrayBindingPattern>node);
560560
case SyntaxKind.BindingElement:
561561
return emitBindingElement(<BindingElement>node);
562562

src/compiler/factory.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,13 @@ namespace ts {
368368
return node;
369369
}
370370

371-
export function createArrayBindingPattern(elements: BindingElement[], location?: TextRange) {
371+
export function createArrayBindingPattern(elements: ArrayBindingElement[], location?: TextRange) {
372372
const node = <ArrayBindingPattern>createNode(SyntaxKind.ArrayBindingPattern, location);
373373
node.elements = createNodeArray(elements);
374374
return node;
375375
}
376376

377-
export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: BindingElement[]) {
377+
export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: ArrayBindingElement[]) {
378378
if (node.elements !== elements) {
379379
return updateNode(createArrayBindingPattern(elements, node), node);
380380
}

src/compiler/parser.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -4815,9 +4815,9 @@ namespace ts {
48154815

48164816
// DECLARATIONS
48174817

4818-
function parseArrayBindingElement(): BindingElement {
4818+
function parseArrayBindingElement(): ArrayBindingElement {
48194819
if (token() === SyntaxKind.CommaToken) {
4820-
return <BindingElement>createNode(SyntaxKind.OmittedExpression);
4820+
return <OmittedExpression>createNode(SyntaxKind.OmittedExpression);
48214821
}
48224822
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
48234823
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
@@ -4842,16 +4842,16 @@ namespace ts {
48424842
return finishNode(node);
48434843
}
48444844

4845-
function parseObjectBindingPattern(): BindingPattern {
4846-
const node = <BindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
4845+
function parseObjectBindingPattern(): ObjectBindingPattern {
4846+
const node = <ObjectBindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
48474847
parseExpected(SyntaxKind.OpenBraceToken);
48484848
node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement);
48494849
parseExpected(SyntaxKind.CloseBraceToken);
48504850
return finishNode(node);
48514851
}
48524852

4853-
function parseArrayBindingPattern(): BindingPattern {
4854-
const node = <BindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
4853+
function parseArrayBindingPattern(): ArrayBindingPattern {
4854+
const node = <ArrayBindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
48554855
parseExpected(SyntaxKind.OpenBracketToken);
48564856
node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement);
48574857
parseExpected(SyntaxKind.CloseBracketToken);

src/compiler/transformers/destructuring.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,15 @@ namespace ts {
326326
}
327327
for (let i = 0; i < numElements; i++) {
328328
const element = elements[i];
329-
if (name.kind === SyntaxKind.ObjectBindingPattern) {
329+
if (isOmittedExpression(element)) {
330+
continue;
331+
}
332+
else if (name.kind === SyntaxKind.ObjectBindingPattern) {
330333
// Rewrite element to a declaration with an initializer that fetches property
331334
const propName = element.propertyName || <Identifier>element.name;
332335
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
333336
}
334-
else if (element.kind !== SyntaxKind.OmittedExpression) {
337+
else {
335338
if (!element.dotDotDotToken) {
336339
// Rewrite element to a declaration that accesses array element at index i
337340
emitBindingElement(element, createElementAccess(value, i));

src/compiler/transformers/es6.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1945,7 +1945,9 @@ namespace ts {
19451945
}
19461946
else {
19471947
for (const element of (<BindingPattern>node).elements) {
1948-
visit(element.name);
1948+
if (!isOmittedExpression(element)) {
1949+
visit(element.name);
1950+
}
19491951
}
19501952
}
19511953
}
@@ -2289,7 +2291,9 @@ namespace ts {
22892291
const name = decl.name;
22902292
if (isBindingPattern(name)) {
22912293
for (const element of name.elements) {
2292-
processLoopVariableDeclaration(element, loopParameters, loopOutParameters);
2294+
if (!isOmittedExpression(element)) {
2295+
processLoopVariableDeclaration(element, loopParameters, loopOutParameters);
2296+
}
22932297
}
22942298
}
22952299
else {

src/compiler/transformers/module/module.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,9 @@ namespace ts {
660660
function addExportMemberAssignmentsForBindingName(resultStatements: Statement[], name: BindingName): void {
661661
if (isBindingPattern(name)) {
662662
for (const element of name.elements) {
663-
addExportMemberAssignmentsForBindingName(resultStatements, element.name);
663+
if (!isOmittedExpression(element)) {
664+
addExportMemberAssignmentsForBindingName(resultStatements, element.name);
665+
}
664666
}
665667
}
666668
else {

src/compiler/transformers/module/system.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1368,7 +1368,11 @@ namespace ts {
13681368
exportedFunctionDeclarations.push(createDeclarationExport(node));
13691369
}
13701370

1371-
function hoistBindingElement(node: VariableDeclaration | BindingElement, isExported: boolean): void {
1371+
function hoistBindingElement(node: VariableDeclaration | ArrayBindingElement, isExported: boolean): void {
1372+
if (isOmittedExpression(node)) {
1373+
return;
1374+
}
1375+
13721376
const name = node.name;
13731377
if (isIdentifier(name)) {
13741378
hoistVariableDeclaration(getSynthesizedClone(name));
@@ -1381,11 +1385,11 @@ namespace ts {
13811385
}
13821386
}
13831387

1384-
function hoistExportedBindingElement(node: VariableDeclaration | BindingElement) {
1388+
function hoistExportedBindingElement(node: VariableDeclaration | ArrayBindingElement) {
13851389
hoistBindingElement(node, /*isExported*/ true);
13861390
}
13871391

1388-
function hoistNonExportedBindingElement(node: VariableDeclaration | BindingElement) {
1392+
function hoistNonExportedBindingElement(node: VariableDeclaration | ArrayBindingElement) {
13891393
hoistBindingElement(node, /*isExported*/ false);
13901394
}
13911395

src/compiler/transformers/ts.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2187,7 +2187,7 @@ namespace ts {
21872187
*
21882188
* @param node The function expression node.
21892189
*/
2190-
function visitFunctionExpression(node: FunctionExpression) {
2190+
function visitFunctionExpression(node: FunctionExpression): Expression {
21912191
if (nodeIsMissing(node.body)) {
21922192
return createOmittedExpression();
21932193
}

src/compiler/types.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -688,14 +688,20 @@ namespace ts {
688688
}
689689

690690
export interface BindingPattern extends Node {
691-
elements: NodeArray<BindingElement>;
691+
elements: NodeArray<BindingElement | ArrayBindingElement>;
692692
}
693693

694694
// @kind(SyntaxKind.ObjectBindingPattern)
695-
export interface ObjectBindingPattern extends BindingPattern { }
695+
export interface ObjectBindingPattern extends BindingPattern {
696+
elements: NodeArray<BindingElement>;
697+
}
698+
699+
export type ArrayBindingElement = BindingElement | OmittedExpression;
696700

697701
// @kind(SyntaxKind.ArrayBindingPattern)
698-
export interface ArrayBindingPattern extends BindingPattern { }
702+
export interface ArrayBindingPattern extends BindingPattern {
703+
elements: NodeArray<ArrayBindingElement>;
704+
}
699705

700706
/**
701707
* Several node kinds share function-like features such as a signature,
@@ -868,7 +874,9 @@ namespace ts {
868874
}
869875

870876
// @kind(SyntaxKind.OmittedExpression)
871-
export interface OmittedExpression extends Expression { }
877+
export interface OmittedExpression extends Expression {
878+
_omittedExpressionBrand: any;
879+
}
872880

873881
// Represents an expression that is elided as part of a transformation to emit comments on a
874882
// not-emitted node. The 'expression' property of a NotEmittedExpression should be emitted.

src/compiler/utilities.ts

+10
Original file line numberDiff line numberDiff line change
@@ -3701,6 +3701,12 @@ namespace ts {
37013701
return node.kind === SyntaxKind.BindingElement;
37023702
}
37033703

3704+
export function isArrayBindingElement(node: Node): node is ArrayBindingElement {
3705+
const kind = node.kind;
3706+
return kind === SyntaxKind.BindingElement
3707+
|| kind === SyntaxKind.OmittedExpression;
3708+
}
3709+
37043710
// Expression
37053711

37063712
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
@@ -3817,6 +3823,10 @@ namespace ts {
38173823
|| isPartiallyEmittedExpression(node);
38183824
}
38193825

3826+
export function isOmittedExpression(node: Node): node is OmittedExpression {
3827+
return node.kind === SyntaxKind.OmittedExpression;
3828+
}
3829+
38203830
// Misc
38213831

38223832
export function isTemplateSpan(node: Node): node is TemplateSpan {

src/compiler/visitor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ namespace ts {
757757

758758
case SyntaxKind.ArrayBindingPattern:
759759
return updateArrayBindingPattern(<ArrayBindingPattern>node,
760-
visitNodes((<ArrayBindingPattern>node).elements, visitor, isBindingElement));
760+
visitNodes((<ArrayBindingPattern>node).elements, visitor, isArrayBindingElement));
761761

762762
case SyntaxKind.BindingElement:
763763
return updateBindingElement(<BindingElement>node,

src/services/completions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ namespace ts.Completions {
11921192
}
11931193
if (canGetType) {
11941194
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
1195-
existingMembers = (<BindingPattern>objectLikeContainer).elements;
1195+
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
11961196
}
11971197
}
11981198
else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [exportArrayBindingPattern.ts]
2+
// issue: https://github.com/Microsoft/TypeScript/issues/10778
3+
const [a, , b] = [1, 2, 3];
4+
export { a, b };
5+
6+
//// [exportArrayBindingPattern.js]
7+
"use strict";
8+
// issue: https://github.com/Microsoft/TypeScript/issues/10778
9+
var _a = [1, 2, 3], a = _a[0], b = _a[2];
10+
exports.a = a;
11+
exports.b = b;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/compiler/exportArrayBindingPattern.ts ===
2+
// issue: https://github.com/Microsoft/TypeScript/issues/10778
3+
const [a, , b] = [1, 2, 3];
4+
>a : Symbol(a, Decl(exportArrayBindingPattern.ts, 1, 7))
5+
>b : Symbol(b, Decl(exportArrayBindingPattern.ts, 1, 11))
6+
7+
export { a, b };
8+
>a : Symbol(a, Decl(exportArrayBindingPattern.ts, 2, 8))
9+
>b : Symbol(b, Decl(exportArrayBindingPattern.ts, 2, 11))
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/exportArrayBindingPattern.ts ===
2+
// issue: https://github.com/Microsoft/TypeScript/issues/10778
3+
const [a, , b] = [1, 2, 3];
4+
>a : number
5+
> : undefined
6+
>b : number
7+
>[1, 2, 3] : [number, number, number]
8+
>1 : number
9+
>2 : number
10+
>3 : number
11+
12+
export { a, b };
13+
>a : number
14+
>b : number
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @module: commonjs
2+
// issue: https://github.com/Microsoft/TypeScript/issues/10778
3+
const [a, , b] = [1, 2, 3];
4+
export { a, b };

0 commit comments

Comments
 (0)