Fix deferred export of array binding pattern

This commit is contained in:
Ron Buckton 2016-09-08 17:14:17 -07:00
parent e16cf96b41
commit c048f7cd6f
18 changed files with 114 additions and 37 deletions

View File

@ -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);

View File

@ -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);
@ -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 => {
@ -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);
@ -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
@ -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);
}
@ -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,
@ -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);
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
@ -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);

View File

@ -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));

View File

@ -1945,7 +1945,9 @@ namespace ts {
}
else {
for (const element of (<BindingPattern>node).elements) {
visit(element.name);
if (!isOmittedExpression(element)) {
visit(element.name);
}
}
}
}
@ -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 {

View File

@ -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 {

View File

@ -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));
@ -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);
}

View File

@ -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();
}

View File

@ -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,
@ -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.

View File

@ -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;
}
// Expression
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
@ -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 {

View File

@ -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,

View File

@ -1192,7 +1192,7 @@ namespace ts.Completions {
}
if (canGetType) {
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
existingMembers = (<BindingPattern>objectLikeContainer).elements;
existingMembers = (<ObjectBindingPattern>objectLikeContainer).elements;
}
}
else {

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -0,0 +1,4 @@
// @module: commonjs
// issue: https://github.com/Microsoft/TypeScript/issues/10778
const [a, , b] = [1, 2, 3];
export { a, b };