fix(semantic): reject jumps across arrow functions (#26357)

Reject labeled and unlabeled `break` and `continue` statements that cross an arrow-function boundary.

For example:
```ts
while (true) {
  (() => {
    break;
  });
}
```

now reports an illegal break, while jumps targeting loops inside the arrow remain valid.
This commit is contained in:
camc314 committed 2026-09-06 07:44:47 +00:00
1 parent 5b3e335484
commit 4b89c7bd55
10 files changed
+145 -20

No files matched your search

@@ -797,7 +797,9 @@ pub fn check_break_statement(stmt: &BreakStatement, ctx: &SemanticBuilder<'_>) {
},
);
}
AstKind::Function(_) | AstKind::StaticBlock(_) => {
AstKind::Function(_)
| AstKind::ArrowFunctionExpression(_)
| AstKind::StaticBlock(_) => {
return stmt.label.as_ref().map_or_else(
|| ctx.error(diagnostics::invalid_break(stmt.span)),
|label| ctx.error(diagnostics::invalid_label_jump_target(label.span)),
@@ -840,7 +842,9 @@ pub fn check_continue_statement(stmt: &ContinueStatement, ctx: &SemanticBuilder<
},
);
}
AstKind::Function(_) | AstKind::StaticBlock(_) => {
AstKind::Function(_)
| AstKind::ArrowFunctionExpression(_)
| AstKind::StaticBlock(_) => {
return stmt.label.as_ref().map_or_else(
|| ctx.error(diagnostics::invalid_continue(stmt.span)),
|label| ctx.error(diagnostics::invalid_label_jump_target(label.span)),
@@ -0,0 +1,7 @@
while (true) { (() => { break; }); }
outer: while (true) { (() => { break outer; }); }
while (true) { (() => { continue; }); }
outer: while (true) { (() => { continue outer; }); }
@@ -0,0 +1,6 @@
(() => {
while (true) { break; }
while (true) { continue; }
outer: while (true) { break outer; }
outer: while (true) { continue outer; }
});
+2 -2
View File
@@ -1,3 +1,3 @@
codegen_misc Summary:
AST Parsed : 80/80 (100.00%)
Positive Passed: 80/80 (100.00%)
AST Parsed : 81/81 (100.00%)
Positive Passed: 81/81 (100.00%)
+2 -2
View File
@@ -1,3 +1,3 @@
formatter_misc Summary:
AST Parsed : 80/80 (100.00%)
Positive Passed: 80/80 (100.00%)
AST Parsed : 81/81 (100.00%)
Positive Passed: 81/81 (100.00%)
+2 -2
View File
@@ -1,6 +1,6 @@
lexer_misc Summary:
AST Parsed : 248/248 (100.00%)
Positive Passed: 246/248 (99.19%)
AST Parsed : 250/250 (100.00%)
Positive Passed: 248/250 (99.20%)
Tokens: tasks/coverage/misc/pass/oxc-2674.tsx
Tokens: tasks/coverage/misc/pass/swc-7187.ts
+35 -3
View File
@@ -1,7 +1,7 @@
parser_misc Summary:
AST Parsed : 80/80 (100.00%)
Positive Passed: 80/80 (100.00%)
Negative Passed: 168/168 (100.00%)
AST Parsed : 81/81 (100.00%)
Positive Passed: 81/81 (100.00%)
Negative Passed: 169/169 (100.00%)
× Cannot assign to 'arguments' in strict mode
╭─[misc/fail/arguments-eval-ambient.ts:2:13]
@@ -136,6 +136,38 @@ Negative Passed: 168/168 (100.00%)
╰────
note: Classes are always strict mode code
× Illegal break statement
╭─[misc/fail/arrow-function-jumps.js:1:25]
1 │ while (true) { (() => { break; }); }
· ──────
2 │
╰────
help: A `break` statement can only be used within an enclosing iteration or switch statement.
× Jump target cannot cross function boundary.
╭─[misc/fail/arrow-function-jumps.js:3:38]
2 │
3 │ outer: while (true) { (() => { break outer; }); }
· ─────
4 │
╰────
× Illegal continue statement: no surrounding iteration statement
╭─[misc/fail/arrow-function-jumps.js:5:25]
4 │
5 │ while (true) { (() => { continue; }); }
· ─────────
6 │
╰────
help: A `continue` statement can only be used within an enclosing `for`, `while` or `do while`
× Jump target cannot cross function boundary.
╭─[misc/fail/arrow-function-jumps.js:7:41]
6 │
7 │ outer: while (true) { (() => { continue outer; }); }
· ─────
╰────
× `await` is only allowed within async functions and at the top levels of modules
╭─[misc/fail/auto-accessor-initializer-await.js:3:18]
2 │ class C {
@@ -3,7 +3,7 @@ commit: b465fdbf
parser_typescript Summary:
AST Parsed : 9783/9783 (100.00%)
Positive Passed: 9783/9783 (100.00%)
Negative Passed: 1647/2636 (62.48%)
Negative Passed: 1649/2636 (62.56%)
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration3.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration4.ts
@@ -174,8 +174,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/contextualTy
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/continueNotInIterationStatement4.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/crashDeclareGlobalTypeofExport.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/crashRegressionTest.ts
@@ -1744,8 +1742,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ParameterLists/parserParameterList17.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement4.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/Statements/parserES5ForOfStatement20.ts
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/Statements/parserForInStatement4.ts
@@ -5188,6 +5184,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
╰────
help: A `continue` statement can only be used within an enclosing `for`, `while` or `do while`
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/compiler/continueNotInIterationStatement4.ts:4:14]
3 │ var x = () => {
4 │ continue TWO;
· ───
5 │ }
╰────
× A `continue` statement can only jump to a label of an enclosing `for`, `while` or `do while` statement.
╭─[typescript/tests/cases/compiler/continueTarget1.ts:1:1]
1 │ target:
@@ -27440,6 +27444,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
╰────
help: A `continue` statement can only be used within an enclosing `for`, `while` or `do while`
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueNotInIterationStatement4.ts:4:14]
3 │ var x = () => {
4 │ continue TWO;
· ───
5 │ }
╰────
× A `continue` statement can only jump to a label of an enclosing `for`, `while` or `do while` statement.
╭─[typescript/tests/cases/conformance/parser/ecmascript5/Statements/ContinueStatements/parser_continueTarget1.ts:1:1]
1 │ target:
@@ -29087,6 +29099,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts:14:15]
13 │ var x = () => {
14 │ break TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts:21:15]
20 │ var fn = function () {
@@ -29128,6 +29148,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts:14:15]
13 │ var x = () => {
14 │ break TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts:21:15]
20 │ var fn = function () {
@@ -29169,6 +29197,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts:14:15]
13 │ var fn = () => {
14 │ break TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts:21:15]
20 │ var fn = function () {
@@ -29210,6 +29246,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts:14:15]
13 │ var x = () => {
14 │ break TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts:21:15]
20 │ var fn = function () {
@@ -29251,6 +29295,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts:14:18]
13 │ var x = () => {
14 │ continue TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts:21:18]
20 │ var fn = function () {
@@ -29292,6 +29344,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts:14:18]
13 │ var x = () => {
14 │ continue TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts:21:18]
20 │ var fn = function () {
@@ -29333,6 +29393,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts:14:18]
13 │ var fn = () => {
14 │ continue TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts:21:18]
20 │ var fn = function () {
@@ -29383,6 +29451,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
9 │
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts:14:18]
13 │ var x = () => {
14 │ continue TWO;
· ───
15 │ }
╰────
× Jump target cannot cross function boundary.
╭─[typescript/tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts:21:18]
20 │ var fn = function () {
+2 -2
View File
@@ -1,6 +1,6 @@
semantic_misc Summary:
AST Parsed : 80/80 (100.00%)
Positive Passed: 76/80 (95.00%)
AST Parsed : 81/81 (100.00%)
Positive Passed: 77/81 (95.06%)
semantic Error: tasks/coverage/misc/pass/declare-let-private.ts
Bindings mismatch:
after transform: ScopeId(0): ["private"]
@@ -1,3 +1,3 @@
transformer_misc Summary:
AST Parsed : 80/80 (100.00%)
Positive Passed: 80/80 (100.00%)
AST Parsed : 81/81 (100.00%)
Positive Passed: 81/81 (100.00%)