Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1150,8 +1150,8 @@ namespace ts {
currentFlow = finishFlowLabel(postExpressionLabel);
}

function bindInitializedVariableFlow(node: VariableDeclaration | BindingElement) {
const name = node.name;
function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
const name = !isOmittedExpression(node) ? node.name : undefined;
if (isBindingPattern(name)) {
for (const child of name.elements) {
bindInitializedVariableFlow(child);
Expand Down
26 changes: 16 additions & 10 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2505,8 +2505,8 @@ namespace ts {
}
}

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

// Return the type implied by an object binding pattern
function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const members = createMap<Symbol>();
let hasComputedProperties = false;
forEach(pattern.elements, e => {
Expand Down Expand Up @@ -3156,11 +3156,12 @@ namespace ts {
// Return the type implied by an array binding pattern
function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
const elements = pattern.elements;
if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) {
const lastElement = lastOrUndefined(elements);
if (elements.length === 0 || (!isOmittedExpression(lastElement) && lastElement.dotDotDotToken)) {
return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType;
}
// If the pattern has at least one element, and no rest element, then it should imply a tuple type.
const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
let result = createTupleType(elementTypes);
if (includePatternInType) {
result = cloneTypeReference(result);
Expand All @@ -3178,8 +3179,8 @@ namespace ts {
// the parameter.
function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean, reportErrors?: boolean): Type {
return pattern.kind === SyntaxKind.ObjectBindingPattern
? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors)
: getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors);
? getTypeFromObjectBindingPattern(<ObjectBindingPattern>pattern, includePatternInType, reportErrors)
: getTypeFromArrayBindingPattern(<ArrayBindingPattern>pattern, includePatternInType, reportErrors);
}

// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
Expand Down Expand Up @@ -12413,7 +12414,7 @@ namespace ts {
function assignBindingElementTypes(node: VariableLikeDeclaration) {
if (isBindingPattern(node.name)) {
for (const element of (<BindingPattern>node.name).elements) {
if (element.kind !== SyntaxKind.OmittedExpression) {
if (!isOmittedExpression(element)) {
if (element.name.kind === SyntaxKind.Identifier) {
getSymbolLinks(getSymbolOfNode(element)).type = getTypeForBindingElement(element);
}
Expand Down Expand Up @@ -13889,7 +13890,12 @@ namespace ts {
pattern: BindingPattern,
predicateVariableNode: Node,
predicateVariableName: string) {
for (const { name } of pattern.elements) {
for (const element of pattern.elements) {
if (isOmittedExpression(element)) {
continue;
}

const name = element.name;
if (name.kind === SyntaxKind.Identifier &&
(<Identifier>name).text === predicateVariableName) {
error(predicateVariableNode,
Expand Down Expand Up @@ -19999,7 +20005,7 @@ namespace ts {
else {
const elements = (<BindingPattern>name).elements;
for (const element of elements) {
if (element.kind !== SyntaxKind.OmittedExpression) {
if (!isOmittedExpression(element)) {
checkGrammarNameInLetOrConstDeclarations(element.name);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,9 +554,9 @@ const _super = (function (geti, seti) {

// Binding patterns
case SyntaxKind.ObjectBindingPattern:
return emitObjectBindingPattern(<BindingPattern>node);
return emitObjectBindingPattern(<ObjectBindingPattern>node);
case SyntaxKind.ArrayBindingPattern:
return emitArrayBindingPattern(<BindingPattern>node);
return emitArrayBindingPattern(<ArrayBindingPattern>node);
case SyntaxKind.BindingElement:
return emitBindingElement(<BindingElement>node);

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,13 @@ namespace ts {
return node;
}

export function createArrayBindingPattern(elements: BindingElement[], location?: TextRange) {
export function createArrayBindingPattern(elements: ArrayBindingElement[], location?: TextRange) {
const node = <ArrayBindingPattern>createNode(SyntaxKind.ArrayBindingPattern, location);
node.elements = createNodeArray(elements);
return node;
}

export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: BindingElement[]) {
export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: ArrayBindingElement[]) {
if (node.elements !== elements) {
return updateNode(createArrayBindingPattern(elements, node), node);
}
Expand Down
12 changes: 6 additions & 6 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4815,9 +4815,9 @@ namespace ts {

// DECLARATIONS

function parseArrayBindingElement(): BindingElement {
function parseArrayBindingElement(): ArrayBindingElement {
if (token() === SyntaxKind.CommaToken) {
return <BindingElement>createNode(SyntaxKind.OmittedExpression);
return <OmittedExpression>createNode(SyntaxKind.OmittedExpression);
}
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
Expand All @@ -4842,16 +4842,16 @@ namespace ts {
return finishNode(node);
}

function parseObjectBindingPattern(): BindingPattern {
const node = <BindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
function parseObjectBindingPattern(): ObjectBindingPattern {
const node = <ObjectBindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
parseExpected(SyntaxKind.OpenBraceToken);
node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement);
parseExpected(SyntaxKind.CloseBraceToken);
return finishNode(node);
}

function parseArrayBindingPattern(): BindingPattern {
const node = <BindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
function parseArrayBindingPattern(): ArrayBindingPattern {
const node = <ArrayBindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
parseExpected(SyntaxKind.OpenBracketToken);
node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement);
parseExpected(SyntaxKind.CloseBracketToken);
Expand Down
7 changes: 5 additions & 2 deletions src/compiler/transformers/destructuring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,15 @@ namespace ts {
}
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (name.kind === SyntaxKind.ObjectBindingPattern) {
if (isOmittedExpression(element)) {
continue;
}
else if (name.kind === SyntaxKind.ObjectBindingPattern) {
// Rewrite element to a declaration with an initializer that fetches property
const propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
}
else if (element.kind !== SyntaxKind.OmittedExpression) {
else {
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, i));
Expand Down
8 changes: 6 additions & 2 deletions src/compiler/transformers/es6.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1945,7 +1945,9 @@ namespace ts {
}
else {
for (const element of (<BindingPattern>node).elements) {
visit(element.name);
if (!isOmittedExpression(element)) {
visit(element.name);
}
}
}
}
Expand Down Expand Up @@ -2289,7 +2291,9 @@ namespace ts {
const name = decl.name;
if (isBindingPattern(name)) {
for (const element of name.elements) {
processLoopVariableDeclaration(element, loopParameters, loopOutParameters);
if (!isOmittedExpression(element)) {
processLoopVariableDeclaration(element, loopParameters, loopOutParameters);
}
}
}
else {
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/transformers/module/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,9 @@ namespace ts {
function addExportMemberAssignmentsForBindingName(resultStatements: Statement[], name: BindingName): void {
if (isBindingPattern(name)) {
for (const element of name.elements) {
addExportMemberAssignmentsForBindingName(resultStatements, element.name);
if (!isOmittedExpression(element)) {
addExportMemberAssignmentsForBindingName(resultStatements, element.name);
}
}
}
else {
Expand Down
10 changes: 7 additions & 3 deletions src/compiler/transformers/module/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1368,7 +1368,11 @@ namespace ts {
exportedFunctionDeclarations.push(createDeclarationExport(node));
}

function hoistBindingElement(node: VariableDeclaration | BindingElement, isExported: boolean): void {
function hoistBindingElement(node: VariableDeclaration | ArrayBindingElement, isExported: boolean): void {
if (isOmittedExpression(node)) {
return;
}

const name = node.name;
if (isIdentifier(name)) {
hoistVariableDeclaration(getSynthesizedClone(name));
Expand All @@ -1381,11 +1385,11 @@ namespace ts {
}
}

function hoistExportedBindingElement(node: VariableDeclaration | BindingElement) {
function hoistExportedBindingElement(node: VariableDeclaration | ArrayBindingElement) {
hoistBindingElement(node, /*isExported*/ true);
}

function hoistNonExportedBindingElement(node: VariableDeclaration | BindingElement) {
function hoistNonExportedBindingElement(node: VariableDeclaration | ArrayBindingElement) {
hoistBindingElement(node, /*isExported*/ false);
}

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,7 @@ namespace ts {
*
* @param node The function expression node.
*/
function visitFunctionExpression(node: FunctionExpression) {
function visitFunctionExpression(node: FunctionExpression): Expression {
if (nodeIsMissing(node.body)) {
return createOmittedExpression();
}
Expand Down
16 changes: 12 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,14 +688,20 @@ namespace ts {
}

export interface BindingPattern extends Node {
elements: NodeArray<BindingElement>;
elements: NodeArray<BindingElement | ArrayBindingElement>;
}

// @kind(SyntaxKind.ObjectBindingPattern)
export interface ObjectBindingPattern extends BindingPattern { }
export interface ObjectBindingPattern extends BindingPattern {
elements: NodeArray<BindingElement>;
}

export type ArrayBindingElement = BindingElement | OmittedExpression;

// @kind(SyntaxKind.ArrayBindingPattern)
export interface ArrayBindingPattern extends BindingPattern { }
export interface ArrayBindingPattern extends BindingPattern {
elements: NodeArray<ArrayBindingElement>;
}

/**
* Several node kinds share function-like features such as a signature,
Expand Down Expand Up @@ -868,7 +874,9 @@ namespace ts {
}

// @kind(SyntaxKind.OmittedExpression)
export interface OmittedExpression extends Expression { }
export interface OmittedExpression extends Expression {
_omittedExpressionBrand: any;
}

// Represents an expression that is elided as part of a transformation to emit comments on a
// not-emitted node. The 'expression' property of a NotEmittedExpression should be emitted.
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3701,6 +3701,12 @@ namespace ts {
return node.kind === SyntaxKind.BindingElement;
}

export function isArrayBindingElement(node: Node): node is ArrayBindingElement {
const kind = node.kind;
return kind === SyntaxKind.BindingElement
|| kind === SyntaxKind.OmittedExpression;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kind of weird that a binding element uses an omitted expression

}

// Expression

export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
Expand Down Expand Up @@ -3817,6 +3823,10 @@ namespace ts {
|| isPartiallyEmittedExpression(node);
}

export function isOmittedExpression(node: Node): node is OmittedExpression {
return node.kind === SyntaxKind.OmittedExpression;
}

// Misc

export function isTemplateSpan(node: Node): node is TemplateSpan {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ namespace ts {

case SyntaxKind.ArrayBindingPattern:
return updateArrayBindingPattern(<ArrayBindingPattern>node,
visitNodes((<ArrayBindingPattern>node).elements, visitor, isBindingElement));
visitNodes((<ArrayBindingPattern>node).elements, visitor, isArrayBindingElement));

case SyntaxKind.BindingElement:
return updateBindingElement(<BindingElement>node,
Expand Down
2 changes: 1 addition & 1 deletion src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ namespace ts.Completions {
}
if (canGetType) {
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
existingMembers = (<BindingPattern>objectLikeContainer).elements;
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
}
}
else {
Expand Down
11 changes: 11 additions & 0 deletions tests/baselines/reference/exportArrayBindingPattern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [exportArrayBindingPattern.ts]
// issue: https://github.com/Microsoft/TypeScript/issues/10778
const [a, , b] = [1, 2, 3];
export { a, b };

//// [exportArrayBindingPattern.js]
"use strict";
// issue: https://github.com/Microsoft/TypeScript/issues/10778
var _a = [1, 2, 3], a = _a[0], b = _a[2];
exports.a = a;
exports.b = b;
10 changes: 10 additions & 0 deletions tests/baselines/reference/exportArrayBindingPattern.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
=== tests/cases/compiler/exportArrayBindingPattern.ts ===
// issue: https://github.com/Microsoft/TypeScript/issues/10778
const [a, , b] = [1, 2, 3];
>a : Symbol(a, Decl(exportArrayBindingPattern.ts, 1, 7))
>b : Symbol(b, Decl(exportArrayBindingPattern.ts, 1, 11))

export { a, b };
>a : Symbol(a, Decl(exportArrayBindingPattern.ts, 2, 8))
>b : Symbol(b, Decl(exportArrayBindingPattern.ts, 2, 11))

15 changes: 15 additions & 0 deletions tests/baselines/reference/exportArrayBindingPattern.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
=== tests/cases/compiler/exportArrayBindingPattern.ts ===
// issue: https://github.com/Microsoft/TypeScript/issues/10778
const [a, , b] = [1, 2, 3];
>a : number
> : undefined
>b : number
>[1, 2, 3] : [number, number, number]
>1 : number
>2 : number
>3 : number

export { a, b };
>a : number
>b : number

4 changes: 4 additions & 0 deletions tests/cases/compiler/exportArrayBindingPattern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @module: commonjs
// issue: https://github.com/Microsoft/TypeScript/issues/10778
const [a, , b] = [1, 2, 3];
export { a, b };