Skip to content

Commit 4d5175b

Browse files
authored
Merge pull request #16341 from Microsoft/fix15651
Fix parameter emit for synthetic function types
2 parents 43e3d60 + 595a815 commit 4d5175b

File tree

4 files changed

+146
-58
lines changed

4 files changed

+146
-58
lines changed

src/compiler/emitter.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ namespace ts {
959959
function emitConstructorType(node: ConstructorTypeNode) {
960960
write("new ");
961961
emitTypeParameters(node, node.typeParameters);
962-
emitParametersForArrow(node, node.parameters);
962+
emitParameters(node, node.parameters);
963963
write(" => ");
964964
emit(node.type);
965965
}
@@ -2283,11 +2283,25 @@ namespace ts {
22832283
emitList(parentNode, parameters, ListFormat.Parameters);
22842284
}
22852285

2286-
function emitParametersForArrow(parentNode: Node, parameters: NodeArray<ParameterDeclaration>) {
2287-
if (parameters &&
2288-
parameters.length === 1 &&
2289-
parameters[0].type === undefined &&
2290-
parameters[0].pos === parentNode.pos) {
2286+
function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
2287+
const parameter = singleOrUndefined(parameters);
2288+
return parameter
2289+
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
2290+
&& !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation
2291+
&& !some(parentNode.decorators) // parent may not have decorators
2292+
&& !some(parentNode.modifiers) // parent may not have modifiers
2293+
&& !some(parentNode.typeParameters) // parent may not have type parameters
2294+
&& !some(parameter.decorators) // parameter may not have decorators
2295+
&& !some(parameter.modifiers) // parameter may not have modifiers
2296+
&& !parameter.dotDotDotToken // parameter may not be rest
2297+
&& !parameter.questionToken // parameter may not be optional
2298+
&& !parameter.type // parameter may not have a type annotation
2299+
&& !parameter.initializer // parameter may not have an initializer
2300+
&& isIdentifier(parameter.name); // parameter name must be identifier
2301+
}
2302+
2303+
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
2304+
if (canEmitSimpleArrowHead(parentNode, parameters)) {
22912305
emit(parameters[0]);
22922306
}
22932307
else {

src/compiler/factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ namespace ts {
228228

229229
// Signature elements
230230

231-
export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
231+
export function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
232232
const node = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
233233
node.name = asName(name);
234234
node.constraint = constraint;

src/harness/unittests/printer.ts

Lines changed: 124 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -81,63 +81,136 @@ namespace ts {
8181

8282
describe("printNode", () => {
8383
const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly");
84-
let sourceFile: SourceFile;
85-
before(() => sourceFile = createSourceFile("source.ts", "", ScriptTarget.ES2015));
86-
// tslint:disable boolean-trivia
87-
const syntheticNode = createClassDeclaration(
88-
undefined,
89-
undefined,
90-
/*name*/ createIdentifier("C"),
91-
undefined,
92-
undefined,
93-
createNodeArray([
94-
createProperty(
95-
undefined,
84+
printsCorrectly("class", {}, printer => printer.printNode(
85+
EmitHint.Unspecified,
86+
createClassDeclaration(
87+
/*decorators*/ undefined,
88+
/*modifiers*/ undefined,
89+
/*name*/ createIdentifier("C"),
90+
/*typeParameters*/ undefined,
91+
/*heritageClauses*/ undefined,
92+
[createProperty(
93+
/*decorators*/ undefined,
9694
createNodeArray([createToken(SyntaxKind.PublicKeyword)]),
9795
createIdentifier("prop"),
98-
undefined,
99-
undefined,
100-
undefined
101-
)
102-
])
103-
);
96+
/*questionToken*/ undefined,
97+
/*type*/ undefined,
98+
/*initializer*/ undefined
99+
)]
100+
),
101+
createSourceFile("source.ts", "", ScriptTarget.ES2015)
102+
));
103+
104+
printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(
105+
EmitHint.Unspecified,
106+
createNamespaceExportDeclaration("B"),
107+
createSourceFile("source.ts", "", ScriptTarget.ES2015)
108+
));
104109

105110
// https://github.com/Microsoft/TypeScript/issues/15971
106-
const classWithOptionalMethodAndProperty = createClassDeclaration(
107-
undefined,
108-
/* modifiers */ createNodeArray([createToken(SyntaxKind.DeclareKeyword)]),
109-
/* name */ createIdentifier("X"),
110-
undefined,
111-
undefined,
112-
createNodeArray([
113-
createMethod(
114-
undefined,
115-
undefined,
116-
undefined,
117-
/* name */ createIdentifier("method"),
118-
/* questionToken */ createToken(SyntaxKind.QuestionToken),
119-
undefined,
120-
undefined,
121-
/* type */ createKeywordTypeNode(SyntaxKind.VoidKeyword),
122-
undefined
111+
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(
112+
EmitHint.Unspecified,
113+
createClassDeclaration(
114+
/*decorators*/ undefined,
115+
/*modifiers*/ [createToken(SyntaxKind.DeclareKeyword)],
116+
/*name*/ createIdentifier("X"),
117+
/*typeParameters*/ undefined,
118+
/*heritageClauses*/ undefined,
119+
[
120+
createMethod(
121+
/*decorators*/ undefined,
122+
/*modifiers*/ undefined,
123+
/*asteriskToken*/ undefined,
124+
/*name*/ createIdentifier("method"),
125+
/*questionToken*/ createToken(SyntaxKind.QuestionToken),
126+
/*typeParameters*/ undefined,
127+
[],
128+
/*type*/ createKeywordTypeNode(SyntaxKind.VoidKeyword),
129+
/*body*/ undefined
130+
),
131+
createProperty(
132+
/*decorators*/ undefined,
133+
/*modifiers*/ undefined,
134+
/*name*/ createIdentifier("property"),
135+
/*questionToken*/ createToken(SyntaxKind.QuestionToken),
136+
/*type*/ createKeywordTypeNode(SyntaxKind.StringKeyword),
137+
/*initializer*/ undefined
138+
),
139+
]
140+
),
141+
createSourceFile("source.ts", "", ScriptTarget.ES2015)
142+
));
143+
144+
// https://github.com/Microsoft/TypeScript/issues/15651
145+
printsCorrectly("functionTypes", {}, printer => printer.printNode(
146+
EmitHint.Unspecified,
147+
createTupleTypeNode([
148+
createFunctionTypeNode(
149+
/*typeArguments*/ undefined,
150+
[createParameter(
151+
/*decorators*/ undefined,
152+
/*modifiers*/ undefined,
153+
/*dotDotDotToken*/ undefined,
154+
createIdentifier("args")
155+
)],
156+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
123157
),
124-
createProperty(
125-
undefined,
126-
undefined,
127-
/* name */ createIdentifier("property"),
128-
/* questionToken */ createToken(SyntaxKind.QuestionToken),
129-
/* type */ createKeywordTypeNode(SyntaxKind.StringKeyword),
130-
undefined
158+
createFunctionTypeNode(
159+
[createTypeParameterDeclaration("T")],
160+
[createParameter(
161+
/*decorators*/ undefined,
162+
/*modifiers*/ undefined,
163+
/*dotDotDotToken*/ undefined,
164+
createIdentifier("args")
165+
)],
166+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
131167
),
132-
])
133-
);
134-
135-
// tslint:enable boolean-trivia
136-
printsCorrectly("class", {}, printer => printer.printNode(EmitHint.Unspecified, syntheticNode, sourceFile));
137-
138-
printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(EmitHint.Unspecified, createNamespaceExportDeclaration("B"), sourceFile));
139-
140-
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(EmitHint.Unspecified, classWithOptionalMethodAndProperty, sourceFile));
168+
createFunctionTypeNode(
169+
/*typeArguments*/ undefined,
170+
[createParameter(
171+
/*decorators*/ undefined,
172+
/*modifiers*/ undefined,
173+
createToken(SyntaxKind.DotDotDotToken),
174+
createIdentifier("args")
175+
)],
176+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
177+
),
178+
createFunctionTypeNode(
179+
/*typeArguments*/ undefined,
180+
[createParameter(
181+
/*decorators*/ undefined,
182+
/*modifiers*/ undefined,
183+
/*dotDotDotToken*/ undefined,
184+
createIdentifier("args"),
185+
createToken(SyntaxKind.QuestionToken)
186+
)],
187+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
188+
),
189+
createFunctionTypeNode(
190+
/*typeArguments*/ undefined,
191+
[createParameter(
192+
/*decorators*/ undefined,
193+
/*modifiers*/ undefined,
194+
/*dotDotDotToken*/ undefined,
195+
createIdentifier("args"),
196+
/*questionToken*/ undefined,
197+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
198+
)],
199+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
200+
),
201+
createFunctionTypeNode(
202+
/*typeArguments*/ undefined,
203+
[createParameter(
204+
/*decorators*/ undefined,
205+
/*modifiers*/ undefined,
206+
/*dotDotDotToken*/ undefined,
207+
createObjectBindingPattern([])
208+
)],
209+
createKeywordTypeNode(SyntaxKind.AnyKeyword)
210+
),
211+
]),
212+
createSourceFile("source.ts", "", ScriptTarget.ES2015)
213+
));
141214
});
142215
});
143216
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[args => any, <T>(args) => any, (...args) => any, (args?) => any, (args: any) => any, ({}) => any]

0 commit comments

Comments
 (0)