Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More rigorous ASI prevention when emitting return/yield #60304

Merged
merged 3 commits into from
Oct 22, 2024
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
93 changes: 83 additions & 10 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3226,17 +3226,90 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
* Wraps an expression in parens if we would emit a leading comment that would introduce a line separator
* between the node and its parent.
*/
function parenthesizeExpressionForNoAsi(node: Expression) {
if (!commentsDisabled && isPartiallyEmittedExpression(node) && willEmitLeadingNewLine(node)) {
const parseNode = getParseTreeNode(node);
if (parseNode && isParenthesizedExpression(parseNode)) {
// If the original node was a parenthesized expression, restore it to preserve comment and source map emit
const parens = factory.createParenthesizedExpression(node.expression);
setOriginalNode(parens, node);
setTextRange(parens, parseNode);
return parens;
function parenthesizeExpressionForNoAsi(node: Expression): Expression {
if (!commentsDisabled) {
switch (node.kind) {
case SyntaxKind.PartiallyEmittedExpression:
if (willEmitLeadingNewLine(node)) {
const parseNode = getParseTreeNode(node);
if (parseNode && isParenthesizedExpression(parseNode)) {
// If the original node was a parenthesized expression, restore it to preserve comment and source map emit
const parens = factory.createParenthesizedExpression((node as PartiallyEmittedExpression).expression);
setOriginalNode(parens, node);
setTextRange(parens, parseNode);
return parens;
}
return factory.createParenthesizedExpression(node);
}
return factory.updatePartiallyEmittedExpression(
node as PartiallyEmittedExpression,
parenthesizeExpressionForNoAsi((node as PartiallyEmittedExpression).expression),
);
case SyntaxKind.PropertyAccessExpression:
return factory.updatePropertyAccessExpression(
node as PropertyAccessExpression,
parenthesizeExpressionForNoAsi((node as PropertyAccessExpression).expression),
(node as PropertyAccessExpression).name,
);
case SyntaxKind.ElementAccessExpression:
return factory.updateElementAccessExpression(
node as ElementAccessExpression,
parenthesizeExpressionForNoAsi((node as ElementAccessExpression).expression),
(node as ElementAccessExpression).argumentExpression,
);
case SyntaxKind.CallExpression:
return factory.updateCallExpression(
node as CallExpression,
parenthesizeExpressionForNoAsi((node as CallExpression).expression),
(node as CallExpression).typeArguments,
(node as CallExpression).arguments,
);
case SyntaxKind.TaggedTemplateExpression:
return factory.updateTaggedTemplateExpression(
node as TaggedTemplateExpression,
parenthesizeExpressionForNoAsi((node as TaggedTemplateExpression).tag),
(node as TaggedTemplateExpression).typeArguments,
(node as TaggedTemplateExpression).template,
);
case SyntaxKind.PostfixUnaryExpression:
return factory.updatePostfixUnaryExpression(
node as PostfixUnaryExpression,
parenthesizeExpressionForNoAsi((node as PostfixUnaryExpression).operand),
);
case SyntaxKind.BinaryExpression:
return factory.updateBinaryExpression(
node as BinaryExpression,
parenthesizeExpressionForNoAsi((node as BinaryExpression).left),
(node as BinaryExpression).operatorToken,
(node as BinaryExpression).right,
);
case SyntaxKind.ConditionalExpression:
return factory.updateConditionalExpression(
node as ConditionalExpression,
parenthesizeExpressionForNoAsi((node as ConditionalExpression).condition),
(node as ConditionalExpression).questionToken,
(node as ConditionalExpression).whenTrue,
(node as ConditionalExpression).colonToken,
(node as ConditionalExpression).whenFalse,
);
case SyntaxKind.AsExpression:
return factory.updateAsExpression(
node as AsExpression,
parenthesizeExpressionForNoAsi((node as AsExpression).expression),
(node as AsExpression).type,
);
case SyntaxKind.SatisfiesExpression:
return factory.updateSatisfiesExpression(
node as SatisfiesExpression,
parenthesizeExpressionForNoAsi((node as SatisfiesExpression).expression),
(node as SatisfiesExpression).type,
);
case SyntaxKind.NonNullExpression:
return factory.updateNonNullExpression(
node as NonNullExpression,
parenthesizeExpressionForNoAsi((node as NonNullExpression).expression),
);
}
return factory.createParenthesizedExpression(node);
}
return node;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//// [tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts] ////

//// [returnStatementNoAsiAfterTransform.ts]
declare var a: any;

function t1() {
return (
// comment
a as any
);
}
function t2() {
return (
// comment
a as any
) + 1;
}
function t3() {
return (
// comment
a as any
) ? 0 : 1;
}
function t4() {
return (
// comment
a as any
).b;
}
function t5() {
return (
// comment
a as any
)[a];
}
function t6() {
return (
// comment
a as any
)();
}
function t7() {
return (
// comment
a as any
)``;
}
function t8() {
return (
// comment
a as any
) as any;
}
function t9() {
return (
// comment
a as any
) satisfies any;
}
function t10() {
return (
// comment
a as any
)!;
}


//// [returnStatementNoAsiAfterTransform.js]
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
return cooked;
};
function t1() {
return (
// comment
a);
}
function t2() {
return (
// comment
a) + 1;
}
function t3() {
return (
// comment
a) ? 0 : 1;
}
function t4() {
return (
// comment
a).b;
}
function t5() {
return (
// comment
a)[a];
}
function t6() {
return (
// comment
a)();
}
function t7() {
return (
// comment
a)(__makeTemplateObject([""], [""]));
}
function t8() {
return (
// comment
a);
}
function t9() {
return (
// comment
a);
}
function t10() {
return (
// comment
a);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//// [tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts] ////

//// [returnStatementNoAsiAfterTransform.ts]
declare var a: any;

function t1() {
return (
// comment
a as any
);
}
function t2() {
return (
// comment
a as any
) + 1;
}
function t3() {
return (
// comment
a as any
) ? 0 : 1;
}
function t4() {
return (
// comment
a as any
).b;
}
function t5() {
return (
// comment
a as any
)[a];
}
function t6() {
return (
// comment
a as any
)();
}
function t7() {
return (
// comment
a as any
)``;
}
function t8() {
return (
// comment
a as any
) as any;
}
function t9() {
return (
// comment
a as any
) satisfies any;
}
function t10() {
return (
// comment
a as any
)!;
}


//// [returnStatementNoAsiAfterTransform.js]
function t1() {
return (
// comment
a);
}
function t2() {
return (
// comment
a) + 1;
}
function t3() {
return (
// comment
a) ? 0 : 1;
}
function t4() {
return (
// comment
a).b;
}
function t5() {
return (
// comment
a)[a];
}
function t6() {
return (
// comment
a)();
}
function t7() {
return (
// comment
a) ``;
}
function t8() {
return (
// comment
a);
}
function t9() {
return (
// comment
a);
}
function t10() {
return (
// comment
a);
}
Loading