Skip to content

Commit 649cd3b

Browse files
committed
Declaration emit fixes for binding pattern in variable statements
Handles #2023
1 parent 983b9f5 commit 649cd3b

File tree

32 files changed

+956
-33
lines changed

32 files changed

+956
-33
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1581,8 +1581,15 @@ module ts {
15811581

15821582
function determineIfDeclarationIsVisible() {
15831583
switch (node.kind) {
1584-
case SyntaxKind.VariableDeclaration:
15851584
case SyntaxKind.BindingElement:
1585+
return isDeclarationVisible(<Declaration>node.parent.parent);
1586+
case SyntaxKind.VariableDeclaration:
1587+
if (isBindingPattern(node.name) &&
1588+
!(<BindingPattern>node.name).elements.length) {
1589+
// If the binding pattern is empty, this variable declaration is not visible
1590+
return false;
1591+
}
1592+
// Otherwise fall through
15861593
case SyntaxKind.ModuleDeclaration:
15871594
case SyntaxKind.ClassDeclaration:
15881595
case SyntaxKind.InterfaceDeclaration:

src/compiler/emitter.ts

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,62 +1024,94 @@ module ts {
10241024
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
10251025
// so there is no check needed to see if declaration is visible
10261026
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
1027-
// If this node is a computed name, it can only be a symbol, because we've already skipped
1028-
// it if it's not a well known symbol. In that case, the text of the name will be exactly
1029-
// what we want, namely the name expression enclosed in brackets.
1030-
writeTextOfNode(currentSourceFile, node.name);
1031-
// If optional property emit ?
1032-
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) {
1033-
write("?");
1034-
}
1035-
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
1036-
emitTypeOfVariableDeclarationFromTypeLiteral(node);
1027+
if (isBindingPattern(node.name)) {
1028+
emitBindingPattern(<BindingPattern>node.name);
10371029
}
1038-
else if (!(node.flags & NodeFlags.Private)) {
1039-
writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
1030+
else {
1031+
// If this node is a computed name, it can only be a symbol, because we've already skipped
1032+
// it if it's not a well known symbol. In that case, the text of the name will be exactly
1033+
// what we want, namely the name expression enclosed in brackets.
1034+
writeTextOfNode(currentSourceFile, node.name);
1035+
// If optional property emit ?
1036+
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) {
1037+
write("?");
1038+
}
1039+
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
1040+
emitTypeOfVariableDeclarationFromTypeLiteral(node);
1041+
}
1042+
else if (!(node.flags & NodeFlags.Private)) {
1043+
writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
1044+
}
10401045
}
10411046
}
10421047

1043-
function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
1044-
var diagnosticMessage: DiagnosticMessage;
1048+
function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult: SymbolAccessiblityResult) {
10451049
if (node.kind === SyntaxKind.VariableDeclaration) {
1046-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1047-
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
1048-
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
1049-
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
1050-
Diagnostics.Exported_variable_0_has_or_is_using_private_name_1;
1050+
return symbolAccesibilityResult.errorModuleName ?
1051+
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
1052+
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
1053+
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
1054+
Diagnostics.Exported_variable_0_has_or_is_using_private_name_1;
10511055
}
10521056
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
10531057
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) {
10541058
// TODO(jfreeman): Deal with computed properties in error reporting.
10551059
if (node.flags & NodeFlags.Static) {
1056-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1057-
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
1058-
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
1059-
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
1060-
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
1060+
return symbolAccesibilityResult.errorModuleName ?
1061+
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
1062+
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
1063+
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
1064+
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
10611065
}
10621066
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
1063-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1064-
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
1065-
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
1066-
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
1067-
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
1067+
return symbolAccesibilityResult.errorModuleName ?
1068+
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
1069+
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
1070+
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
1071+
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
10681072
}
10691073
else {
10701074
// Interfaces cannot have types that cannot be named
1071-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1072-
Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
1073-
Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
1075+
return symbolAccesibilityResult.errorModuleName ?
1076+
Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
1077+
Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
10741078
}
10751079
}
1080+
}
10761081

1082+
function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
1083+
var diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
10771084
return diagnosticMessage !== undefined ? {
10781085
diagnosticMessage,
10791086
errorNode: node,
10801087
typeName: node.name
10811088
} : undefined;
10821089
}
1090+
1091+
function emitBindingPattern(bindingPattern: BindingPattern) {
1092+
emitCommaList(bindingPattern.elements, emitBindingElement);
1093+
}
1094+
1095+
function emitBindingElement(bindingElement: BindingElement) {
1096+
function getBindingElementTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
1097+
var diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
1098+
return diagnosticMessage !== undefined ? {
1099+
diagnosticMessage,
1100+
errorNode: bindingElement,
1101+
typeName: bindingElement.name
1102+
} : undefined;
1103+
}
1104+
1105+
if (bindingElement.name) {
1106+
if (isBindingPattern(bindingElement.name)) {
1107+
emitBindingPattern(<BindingPattern>bindingElement.name);
1108+
}
1109+
else {
1110+
writeTextOfNode(currentSourceFile, bindingElement.name);
1111+
writeTypeOfDeclaration(bindingElement, /*type*/ undefined, getBindingElementTypeVisibilityError);
1112+
}
1113+
}
1114+
}
10831115
}
10841116

10851117
function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableLikeDeclaration) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [declarationEmitDestructuringArrayPattern1.ts]
2+
3+
var [] = [1, "hello"]; // Dont emit anything
4+
var [x] = [1, "hello"]; // emit x: number
5+
var [x1, y1] = [1, "hello"]; // emit x1: number, y1: string
6+
var [, , z1] = [0, 1, 2]; // emit z1: number
7+
8+
var a = [1, "hello"];
9+
var [x2] = a; // emit x2: number | string
10+
var [x3, y3, z3] = a; // emit x3, y3, z3
11+
12+
//// [declarationEmitDestructuringArrayPattern1.js]
13+
var _a = [1, "hello"]; // Dont emit anything
14+
var x = ([1, "hello"])[0]; // emit x: number
15+
var _b = [1, "hello"], x1 = _b[0], y1 = _b[1]; // emit x1: number, y1: string
16+
var _c = [0, 1, 2], z1 = _c[2]; // emit z1: number
17+
var a = [1, "hello"];
18+
var x2 = a[0]; // emit x2: number | string
19+
var x3 = a[0], y3 = a[1], z3 = a[2]; // emit x3, y3, z3
20+
21+
22+
//// [declarationEmitDestructuringArrayPattern1.d.ts]
23+
declare var x: number;
24+
declare var x1: number, y1: string;
25+
declare var z1: number;
26+
declare var a: (string | number)[];
27+
declare var x2: string | number;
28+
declare var x3: string | number, y3: string | number, z3: string | number;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
=== tests/cases/compiler/declarationEmitDestructuringArrayPattern1.ts ===
2+
3+
var [] = [1, "hello"]; // Dont emit anything
4+
>[1, "hello"] : (string | number)[]
5+
6+
var [x] = [1, "hello"]; // emit x: number
7+
>x : number
8+
>[1, "hello"] : [number, string]
9+
10+
var [x1, y1] = [1, "hello"]; // emit x1: number, y1: string
11+
>x1 : number
12+
>y1 : string
13+
>[1, "hello"] : [number, string]
14+
15+
var [, , z1] = [0, 1, 2]; // emit z1: number
16+
>z1 : number
17+
>[0, 1, 2] : [number, number, number]
18+
19+
var a = [1, "hello"];
20+
>a : (string | number)[]
21+
>[1, "hello"] : (string | number)[]
22+
23+
var [x2] = a; // emit x2: number | string
24+
>x2 : string | number
25+
>a : (string | number)[]
26+
27+
var [x3, y3, z3] = a; // emit x3, y3, z3
28+
>x3 : string | number
29+
>y3 : string | number
30+
>z3 : string | number
31+
>a : (string | number)[]
32+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [declarationEmitDestructuringArrayPattern2.ts]
2+
var [x10, [y10, [z10]]] = [1, ["hello", [true]]];
3+
4+
var [x11 = 0, y11 = ""] = [1, "hello"];
5+
var [a11, b11, c11] = [];
6+
7+
var [a2, [b2, { x12, y12: c2 }]=["abc", { x12: 10, y12: false }]] = [1, ["hello", { x12: 5, y12: true }]];
8+
9+
var [x13, y13] = [1, "hello"];
10+
var [a3, b3] = [[x13, y13], { x: x13, y: y13 }];
11+
12+
13+
//// [declarationEmitDestructuringArrayPattern2.js]
14+
var _a = [1, ["hello", [true]]], x10 = _a[0], _b = _a[1], y10 = _b[0], z10 = _b[1][0];
15+
var _c = [1, "hello"], _d = _c[0], x11 = _d === void 0 ? 0 : _d, _e = _c[1], y11 = _e === void 0 ? "" : _e;
16+
var _f = [], a11 = _f[0], b11 = _f[1], c11 = _f[2];
17+
var _g = [1, ["hello", { x12: 5, y12: true }]], a2 = _g[0], _h = _g[1], _j = _h === void 0 ? ["abc", { x12: 10, y12: false }] : _h, b2 = _j[0], _k = _j[1], x12 = _k.x12, c2 = _k.y12;
18+
var _l = [1, "hello"], x13 = _l[0], y13 = _l[1];
19+
var _m = [[x13, y13], { x: x13, y: y13 }], a3 = _m[0], b3 = _m[1];
20+
21+
22+
//// [declarationEmitDestructuringArrayPattern2.d.ts]
23+
declare var x10: number, y10: string, z10: boolean;
24+
declare var x11: number, y11: string;
25+
declare var a11: any, b11: any, c11: any;
26+
declare var a2: number, b2: string, x12: number, c2: boolean;
27+
declare var x13: number, y13: string;
28+
declare var a3: (string | number)[], b3: {
29+
x: number;
30+
y: string;
31+
};
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
=== tests/cases/compiler/declarationEmitDestructuringArrayPattern2.ts ===
2+
var [x10, [y10, [z10]]] = [1, ["hello", [true]]];
3+
>x10 : number
4+
>y10 : string
5+
>z10 : boolean
6+
>[1, ["hello", [true]]] : [number, [string, [boolean]]]
7+
>["hello", [true]] : [string, [boolean]]
8+
>[true] : [boolean]
9+
10+
var [x11 = 0, y11 = ""] = [1, "hello"];
11+
>x11 : number
12+
>y11 : string
13+
>[1, "hello"] : [number, string]
14+
15+
var [a11, b11, c11] = [];
16+
>a11 : any
17+
>b11 : any
18+
>c11 : any
19+
>[] : undefined[]
20+
21+
var [a2, [b2, { x12, y12: c2 }]=["abc", { x12: 10, y12: false }]] = [1, ["hello", { x12: 5, y12: true }]];
22+
>a2 : number
23+
>b2 : string
24+
>x12 : number
25+
>y12 : unknown
26+
>c2 : boolean
27+
>["abc", { x12: 10, y12: false }] : [string, { x12: number; y12: boolean; }]
28+
>{ x12: 10, y12: false } : { x12: number; y12: boolean; }
29+
>x12 : number
30+
>y12 : boolean
31+
>[1, ["hello", { x12: 5, y12: true }]] : [number, [string, { x12: number; y12: boolean; }]]
32+
>["hello", { x12: 5, y12: true }] : [string, { x12: number; y12: boolean; }]
33+
>{ x12: 5, y12: true } : { x12: number; y12: boolean; }
34+
>x12 : number
35+
>y12 : boolean
36+
37+
var [x13, y13] = [1, "hello"];
38+
>x13 : number
39+
>y13 : string
40+
>[1, "hello"] : [number, string]
41+
42+
var [a3, b3] = [[x13, y13], { x: x13, y: y13 }];
43+
>a3 : (string | number)[]
44+
>b3 : { x: number; y: string; }
45+
>[[x13, y13], { x: x13, y: y13 }] : [(string | number)[], { x: number; y: string; }]
46+
>[x13, y13] : (string | number)[]
47+
>x13 : number
48+
>y13 : string
49+
>{ x: x13, y: y13 } : { x: number; y: string; }
50+
>x : number
51+
>x13 : number
52+
>y : string
53+
>y13 : string
54+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [declarationEmitDestructuringArrayPattern3.ts]
2+
module M {
3+
export var [a, b] = [1, 2];
4+
}
5+
6+
//// [declarationEmitDestructuringArrayPattern3.js]
7+
var M;
8+
(function (M) {
9+
_a = [1, 2], M.a = _a[0], M.b = _a[1];
10+
var _a;
11+
})(M || (M = {}));
12+
13+
14+
//// [declarationEmitDestructuringArrayPattern3.d.ts]
15+
declare module M {
16+
var a: number, b: number;
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/declarationEmitDestructuringArrayPattern3.ts ===
2+
module M {
3+
>M : typeof M
4+
5+
export var [a, b] = [1, 2];
6+
>a : number
7+
>b : number
8+
>[1, 2] : [number, number]
9+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [declarationEmitDestructuringArrayPattern4.ts]
2+
var [...a5] = [1, 2, 3];
3+
var [x14, ...a6] = [1, 2, 3];
4+
var [x15, y15, ...a7] = [1, 2, 3];
5+
var [x16, y16, z16, ...a8] = [1, 2, 3];
6+
7+
var [...a9] = [1, "hello", true];
8+
var [x17, ...a10] = [1, "hello", true];
9+
var [x18, y18, ...a12] = [1, "hello", true];
10+
var [x19, y19, z19, ...a13] = [1, "hello", true];
11+
12+
//// [declarationEmitDestructuringArrayPattern4.js]
13+
var _a = [1, 2, 3], a5 = _a.slice(0);
14+
var _b = [1, 2, 3], x14 = _b[0], a6 = _b.slice(1);
15+
var _c = [1, 2, 3], x15 = _c[0], y15 = _c[1], a7 = _c.slice(2);
16+
var _d = [1, 2, 3], x16 = _d[0], y16 = _d[1], z16 = _d[2], a8 = _d.slice(3);
17+
var _e = [1, "hello", true], a9 = _e.slice(0);
18+
var _f = [1, "hello", true], x17 = _f[0], a10 = _f.slice(1);
19+
var _g = [1, "hello", true], x18 = _g[0], y18 = _g[1], a12 = _g.slice(2);
20+
var _h = [1, "hello", true], x19 = _h[0], y19 = _h[1], z19 = _h[2], a13 = _h.slice(3);
21+
22+
23+
//// [declarationEmitDestructuringArrayPattern4.d.ts]
24+
declare var a5: number[];
25+
declare var x14: number, a6: number[];
26+
declare var x15: number, y15: number, a7: number[];
27+
declare var x16: number, y16: number, z16: number, a8: number[];
28+
declare var a9: (string | number | boolean)[];
29+
declare var x17: string | number | boolean, a10: (string | number | boolean)[];
30+
declare var x18: string | number | boolean, y18: string | number | boolean, a12: (string | number | boolean)[];
31+
declare var x19: string | number | boolean, y19: string | number | boolean, z19: string | number | boolean, a13: (string | number | boolean)[];
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/declarationEmitDestructuringArrayPattern4.ts ===
2+
var [...a5] = [1, 2, 3];
3+
>a5 : number[]
4+
>[1, 2, 3] : number[]
5+
6+
var [x14, ...a6] = [1, 2, 3];
7+
>x14 : number
8+
>a6 : number[]
9+
>[1, 2, 3] : number[]
10+
11+
var [x15, y15, ...a7] = [1, 2, 3];
12+
>x15 : number
13+
>y15 : number
14+
>a7 : number[]
15+
>[1, 2, 3] : number[]
16+
17+
var [x16, y16, z16, ...a8] = [1, 2, 3];
18+
>x16 : number
19+
>y16 : number
20+
>z16 : number
21+
>a8 : number[]
22+
>[1, 2, 3] : number[]
23+
24+
var [...a9] = [1, "hello", true];
25+
>a9 : (string | number | boolean)[]
26+
>[1, "hello", true] : (string | number | boolean)[]
27+
28+
var [x17, ...a10] = [1, "hello", true];
29+
>x17 : string | number | boolean
30+
>a10 : (string | number | boolean)[]
31+
>[1, "hello", true] : (string | number | boolean)[]
32+
33+
var [x18, y18, ...a12] = [1, "hello", true];
34+
>x18 : string | number | boolean
35+
>y18 : string | number | boolean
36+
>a12 : (string | number | boolean)[]
37+
>[1, "hello", true] : (string | number | boolean)[]
38+
39+
var [x19, y19, z19, ...a13] = [1, "hello", true];
40+
>x19 : string | number | boolean
41+
>y19 : string | number | boolean
42+
>z19 : string | number | boolean
43+
>a13 : (string | number | boolean)[]
44+
>[1, "hello", true] : (string | number | boolean)[]
45+

0 commit comments

Comments
 (0)