Skip to content

Commit 5979dac

Browse files
author
Yui T
committed
Correctly emit bidning pattern with initializer and rest
1 parent b5065f1 commit 5979dac

10 files changed

+236
-24
lines changed

src/compiler/declarationEmitter.ts

+77-20
Original file line numberDiff line numberDiff line change
@@ -1291,8 +1291,10 @@ module ts {
12911291
write("...");
12921292
}
12931293
if (isBindingPattern(node.name)) {
1294-
// By emitting binding pattern as binding pattern in function parameters, language service can provide better signature help
1295-
write(getTextOfNode(node.name));
1294+
// For bindingPattern, we can't simply writeTextOfNode from the source file
1295+
// because we want to omit the initializer and using writeTextOfNode will result in initializer get emitted.
1296+
// Therefore, we will have to recursively emit each element in the bindingPattern.
1297+
emitBindingPattern(<BindingPattern>node.name);
12961298
}
12971299
else {
12981300
writeTextOfNode(currentSourceFile, node.name);
@@ -1312,72 +1314,127 @@ module ts {
13121314
}
13131315

13141316
function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
1315-
let diagnosticMessage: DiagnosticMessage;
1317+
let diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
1318+
return diagnosticMessage !== undefined ? {
1319+
diagnosticMessage,
1320+
errorNode: node,
1321+
typeName: node.name
1322+
} : undefined;
1323+
}
1324+
1325+
function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult: SymbolAccessiblityResult) {
13161326
switch (node.parent.kind) {
13171327
case SyntaxKind.Constructor:
1318-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1328+
return symbolAccesibilityResult.errorModuleName ?
13191329
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
13201330
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
13211331
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
13221332
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1;
1323-
break;
13241333

13251334
case SyntaxKind.ConstructSignature:
13261335
// Interfaces cannot have parameter types that cannot be named
1327-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1336+
return symbolAccesibilityResult.errorModuleName ?
13281337
Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
13291338
Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
1330-
break;
13311339

13321340
case SyntaxKind.CallSignature:
13331341
// Interfaces cannot have parameter types that cannot be named
1334-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1342+
return symbolAccesibilityResult.errorModuleName ?
13351343
Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
13361344
Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
1337-
break;
13381345

13391346
case SyntaxKind.MethodDeclaration:
13401347
case SyntaxKind.MethodSignature:
13411348
if (node.parent.flags & NodeFlags.Static) {
1342-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1349+
return symbolAccesibilityResult.errorModuleName ?
13431350
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
13441351
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
13451352
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
13461353
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
13471354
}
13481355
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
1349-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1356+
return symbolAccesibilityResult.errorModuleName ?
13501357
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
13511358
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
13521359
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
13531360
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
13541361
}
13551362
else {
13561363
// Interfaces cannot have parameter types that cannot be named
1357-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1364+
return symbolAccesibilityResult.errorModuleName ?
13581365
Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
13591366
Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
13601367
}
1361-
break;
13621368

13631369
case SyntaxKind.FunctionDeclaration:
1364-
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
1370+
return symbolAccesibilityResult.errorModuleName ?
13651371
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
13661372
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
13671373
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
13681374
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1;
1369-
break;
13701375

13711376
default:
13721377
Debug.fail("This is unknown parent for parameter: " + node.parent.kind);
13731378
}
1379+
}
13741380

1375-
return {
1376-
diagnosticMessage,
1377-
errorNode: node,
1378-
typeName: node.name
1379-
};
1381+
function emitBindingPattern(bindingPattern: BindingPattern) {
1382+
// We have to explicitly emit square bracket and bracket because these tokens are not store inside the node.
1383+
if (bindingPattern.kind === SyntaxKind.ObjectBindingPattern) {
1384+
write("{");
1385+
emitCommaList(bindingPattern.elements, emitBindingElement);
1386+
write("}");
1387+
}
1388+
else if (bindingPattern.kind === SyntaxKind.ArrayBindingPattern) {
1389+
write("[");
1390+
emitCommaList(bindingPattern.elements, emitBindingElement);
1391+
write("]");
1392+
}
13801393
}
1394+
1395+
function emitBindingElement(bindingElement: BindingElement) {
1396+
function getBindingElementTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
1397+
let diagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
1398+
return diagnosticMessage !== undefined ? {
1399+
diagnosticMessage,
1400+
errorNode: bindingElement,
1401+
typeName: bindingElement.name
1402+
} : undefined;
1403+
}
1404+
1405+
if (bindingElement.propertyName) {
1406+
// bindingElement has propertyName property in the following case:
1407+
// { y: [a,b,c] ...} -> bindingPattern will have a property called propertyName for "y"
1408+
// We have to explicitly emit the propertyName before descending into its binding elements.
1409+
// Example:
1410+
// original: function foo({y: [a,b,c]}) {}
1411+
// emit : declare function foo({y: [a, b, c]}: { y: [any, any, any] }) void;
1412+
writeTextOfNode(currentSourceFile, bindingElement.propertyName);
1413+
write(": ");
1414+
1415+
// If bindingElement has propertyName property, then its name must be another bindingPattern of SyntaxKind.ObjectBindingPattern
1416+
emitBindingPattern(<BindingPattern>bindingElement.name);
1417+
}
1418+
else if (bindingElement.name) {
1419+
if (isBindingPattern(bindingElement.name)) {
1420+
// If it is a nested binding pattern, we will recursively descend into each element and emit each one separately.
1421+
// In the case of rest element, we will omit rest element.
1422+
// Example:
1423+
// original: function foo([a, [[b]], c] = [1,[["string"]], 3]) {}
1424+
// emit : declare function foo([a, [[b]], c]: [number, [[string]], number]): void;
1425+
// original with rest: function foo([a ...c]) {}
1426+
// emit : declare function foo([a, c]): void;
1427+
emitBindingPattern(<BindingPattern>bindingElement.name);
1428+
}
1429+
else {
1430+
// If the node is just an identifier, we will simply emit the text associated with the node's name
1431+
// Example:
1432+
// original: function foo({y = 10, x}) {}
1433+
// emit : declare function foo({y, x}: {number, any}): void;
1434+
writeTextOfNode(currentSourceFile, bindingElement.name);
1435+
}
1436+
}
1437+
}
13811438
}
13821439

13831440
function emitNode(node: Node) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//// [declarationEmitDestructuringArrayPattern6.ts]
2+
function f({x = 10, y: [a, b, c, d] = [1, 2, 3, 4]} = { x: 10, y: [2, 4, 6, 8] }) { }
3+
function g([a, b, c, d] = [1, 2, 3, 4]) { }
4+
function h([a, [b], [[c]], {x = 10, y: [a, b, c], z: {a1, b1}}]){ }
5+
function h1([a, [b], [[c]], {x = 10, y = [1, 2, 3], z: {a1, b1}}]){ }
6+
7+
//// [declarationEmitDestructuringArrayPattern6.js]
8+
function f(_a) {
9+
var _b = _a === void 0 ? {
10+
x: 10,
11+
y: [
12+
2,
13+
4,
14+
6,
15+
8
16+
]
17+
} : _a, _c = _b.x, x = _c === void 0 ? 10 : _c, _d = _b.y, _e = _d === void 0 ? [
18+
1,
19+
2,
20+
3,
21+
4
22+
] : _d, a = _e[0], b = _e[1], c = _e[2], d = _e[3];
23+
}
24+
function g(_a) {
25+
var _b = _a === void 0 ? [
26+
1,
27+
2,
28+
3,
29+
4
30+
] : _a, a = _b[0], b = _b[1], c = _b[2], d = _b[3];
31+
}
32+
function h(_a) {
33+
var a = _a[0], b = _a[1][0], c = _a[2][0][0], _b = _a[3], _c = _b.x, x = _c === void 0 ? 10 : _c, _d = _b.y, a = _d[0], b = _d[1], c = _d[2], _e = _b.z, a1 = _e.a1, b1 = _e.b1;
34+
}
35+
function h1(_a) {
36+
var a = _a[0], b = _a[1][0], c = _a[2][0][0], _b = _a[3], _c = _b.x, x = _c === void 0 ? 10 : _c, _d = _b.y, y = _d === void 0 ? [
37+
1,
38+
2,
39+
3
40+
] : _d, _e = _b.z, a1 = _e.a1, b1 = _e.b1;
41+
}
42+
43+
44+
//// [declarationEmitDestructuringArrayPattern6.d.ts]
45+
declare function f({x, y: [a, b, c, d]}?: {
46+
x: number;
47+
y: [number, number, number, number];
48+
}): void;
49+
declare function g([a, b, c, d]?: [number, number, number, number]): void;
50+
declare function h([a, [b], [[c]], {x, y: [a, b, c], z: {a1, b1}}]: [any, [any], [[any]], {
51+
x?: number;
52+
y: [any, any, any];
53+
z: {
54+
a1: any;
55+
b1: any;
56+
};
57+
}]): void;
58+
declare function h1([a, [b], [[c]], {x, y, z: {a1, b1}}]: [any, [any], [[any]], {
59+
x?: number;
60+
y?: number[];
61+
z: {
62+
a1: any;
63+
b1: any;
64+
};
65+
}]): void;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/declarationEmitDestructuringArrayPattern6.ts ===
2+
function f({x = 10, y: [a, b, c, d] = [1, 2, 3, 4]} = { x: 10, y: [2, 4, 6, 8] }) { }
3+
>f : ({x = 10, y: [a, b, c, d] = [1, 2, 3, 4]}?: { x: number; y: [number, number, number, number]; }) => void
4+
>x : number
5+
>y : unknown
6+
>a : number
7+
>b : number
8+
>c : number
9+
>d : number
10+
>[1, 2, 3, 4] : [number, number, number, number]
11+
>{ x: 10, y: [2, 4, 6, 8] } : { x: number; y: [number, number, number, number]; }
12+
>x : number
13+
>y : [number, number, number, number]
14+
>[2, 4, 6, 8] : [number, number, number, number]
15+
16+
function g([a, b, c, d] = [1, 2, 3, 4]) { }
17+
>g : ([a, b, c, d]?: [number, number, number, number]) => void
18+
>a : number
19+
>b : number
20+
>c : number
21+
>d : number
22+
>[1, 2, 3, 4] : [number, number, number, number]
23+
24+
function h([a, [b], [[c]], {x = 10, y: [a, b, c], z: {a1, b1}}]){ }
25+
>h : ([a, [b], [[c]], {x = 10, y: [a, b, c], z: {a1, b1}}]: [any, [any], [[any]], { x?: number; y: [any, any, any]; z: { a1: any; b1: any; }; }]) => void
26+
>a : any
27+
>b : any
28+
>c : any
29+
>x : number
30+
>y : unknown
31+
>a : any
32+
>b : any
33+
>c : any
34+
>z : unknown
35+
>a1 : any
36+
>b1 : any
37+
38+
function h1([a, [b], [[c]], {x = 10, y = [1, 2, 3], z: {a1, b1}}]){ }
39+
>h1 : ([a, [b], [[c]], {x = 10, y = [1, 2, 3], z: {a1, b1}}]: [any, [any], [[any]], { x?: number; y?: number[]; z: { a1: any; b1: any; }; }]) => void
40+
>a : any
41+
>b : any
42+
>c : any
43+
>x : number
44+
>y : number[]
45+
>[1, 2, 3] : number[]
46+
>z : unknown
47+
>a1 : any
48+
>b1 : any
49+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [declarationEmitDestructuringArrayPattern7.ts]
2+
function bar([x, z, ...w]) { }
3+
function foo([x, ...y] = [1, "string", true]) { }
4+
5+
//// [declarationEmitDestructuringArrayPattern7.js]
6+
function bar(_a) {
7+
var x = _a[0], z = _a[1], w = _a.slice(2);
8+
}
9+
function foo(_a) {
10+
var _b = _a === void 0 ? [
11+
1,
12+
"string",
13+
true
14+
] : _a, x = _b[0], y = _b.slice(1);
15+
}
16+
17+
18+
//// [declarationEmitDestructuringArrayPattern7.d.ts]
19+
declare function bar([x, z, w]: any[]): void;
20+
declare function foo([x, y]?: (string | number | boolean)[]): void;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/compiler/declarationEmitDestructuringArrayPattern7.ts ===
2+
function bar([x, z, ...w]) { }
3+
>bar : ([x, z, ...w]: any[]) => void
4+
>x : any
5+
>z : any
6+
>w : any[]
7+
8+
function foo([x, ...y] = [1, "string", true]) { }
9+
>foo : ([x, ...y]?: (string | number | boolean)[]) => void
10+
>x : string | number | boolean
11+
>y : (string | number | boolean)[]
12+
>[1, "string", true] : (string | number | boolean)[]
13+

tests/baselines/reference/declarationEmitDestructuringOptionalBindingParametersInOverloads.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function foo2() {
2626

2727
//// [declarationEmitDestructuringOptionalBindingParametersInOverloads.d.ts]
2828
declare function foo([x, y, z]?: [string, number, boolean]): any;
29-
declare function foo2({ x, y, z }?: {
29+
declare function foo2({x, y, z}?: {
3030
x: string;
3131
y: number;
3232
z: boolean;

tests/baselines/reference/declarationEmitDestructuringParameterProperties.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ declare type ObjType1 = {
5757
};
5858
declare class C3 {
5959
x: number, y: string, z: boolean;
60-
constructor({ x, y, z }: ObjType1);
60+
constructor({x, y, z}: ObjType1);
6161
}

tests/baselines/reference/declarationEmitDestructuringWithOptionalBindingParameters.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ function foo1(_a) {
1414

1515

1616
//// [declarationEmitDestructuringWithOptionalBindingParameters.d.ts]
17-
declare function foo([x,y,z]?: [string, number, boolean]): void;
18-
declare function foo1({ x, y, z }?: {
17+
declare function foo([x, y, z]?: [string, number, boolean]): void;
18+
declare function foo1({x, y, z}?: {
1919
x: string;
2020
y: number;
2121
z: boolean;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @declaration: true
2+
function f({x = 10, y: [a, b, c, d] = [1, 2, 3, 4]} = { x: 10, y: [2, 4, 6, 8] }) { }
3+
function g([a, b, c, d] = [1, 2, 3, 4]) { }
4+
function h([a, [b], [[c]], {x = 10, y: [a, b, c], z: {a1, b1}}]){ }
5+
function h1([a, [b], [[c]], {x = 10, y = [1, 2, 3], z: {a1, b1}}]){ }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// @declaration: true
2+
function bar([x, z, ...w]) { }
3+
function foo([x, ...y] = [1, "string", true]) { }

0 commit comments

Comments
 (0)