Skip to content

Commit 7e24fbf

Browse files
committed
fix: improve confusing TS1107 error for mislabeled jump targets
Improve diagnostics by not eagerly reporting 'Jump target cannot cross function boundary' until encountering the actual target label. This correctly emits the TS1104 or TS1116 errors if the target lacks an enclosing iteration or switch statement. Fixes: #30408
1 parent 9059e5b commit 7e24fbf

9 files changed

Lines changed: 189 additions & 7 deletions

File tree

src/compiler/checker.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53028,15 +53028,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5302853028

5302953029
function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean {
5303053030
let current: Node = node;
53031+
let crossedFunctionBoundary = false;
53032+
5303153033
while (current) {
5303253034
if (isFunctionLikeOrClassStaticBlockDeclaration(current)) {
53033-
return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary);
53035+
crossedFunctionBoundary = true;
5303453036
}
5303553037

5303653038
switch (current.kind) {
5303753039
case SyntaxKind.LabeledStatement:
5303853040
if (node.label && (current as LabeledStatement).label.escapedText === node.label.escapedText) {
5303953041
// found matching label - verify that label usage is correct
53042+
53043+
if (crossedFunctionBoundary) {
53044+
return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary);
53045+
}
53046+
5304053047
// continue can only target labels that are on iteration statements
5304153048
const isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement
5304253049
&& !isIterationStatement((current as LabeledStatement).statement, /*lookInLabeledStatements*/ true);
@@ -53051,12 +53058,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
5305153058
case SyntaxKind.SwitchStatement:
5305253059
if (node.kind === SyntaxKind.BreakStatement && !node.label) {
5305353060
// unlabeled break within switch statement - ok
53061+
if (crossedFunctionBoundary) {
53062+
return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary);
53063+
}
5305453064
return false;
5305553065
}
5305653066
break;
5305753067
default:
5305853068
if (isIterationStatement(current, /*lookInLabeledStatements*/ false) && !node.label) {
5305953069
// unlabeled break or continue within iteration statement - ok
53070+
if (crossedFunctionBoundary) {
53071+
return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary);
53072+
}
5306053073
return false;
5306153074
}
5306253075
break;

tests/baselines/reference/invalidContinueInDownlevelAsync.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
invalidContinueInDownlevelAsync.ts(3,9): error TS1107: Jump target cannot cross function boundary.
1+
invalidContinueInDownlevelAsync.ts(3,9): error TS1104: A 'continue' statement can only be used within an enclosing iteration statement.
22

33

44
==== invalidContinueInDownlevelAsync.ts (1 errors) ====
55
async function func() {
66
if (true) {
77
continue;
88
~~~~~~~~~
9-
!!! error TS1107: Jump target cannot cross function boundary.
9+
!!! error TS1104: A 'continue' statement can only be used within an enclosing iteration statement.
1010
}
1111
else {
1212
await 1;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
issue30408.ts(4,9): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement.
2+
issue30408.ts(12,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement.
3+
4+
5+
==== issue30408.ts (2 errors) ====
6+
function foo() {
7+
for (let i = 0; i < 10; i++) {
8+
console.log(`${i}`);
9+
continue loopend;
10+
~~~~~~~~~~~~~~~~~
11+
!!! error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement.
12+
}
13+
14+
loopend:
15+
console.log('end of loop');
16+
}
17+
18+
function bar() {
19+
continue loopend;
20+
~~~~~~~~~~~~~~~~~
21+
!!! error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement.
22+
}
23+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [tests/cases/compiler/issue30408.ts] ////
2+
3+
//// [issue30408.ts]
4+
function foo() {
5+
for (let i = 0; i < 10; i++) {
6+
console.log(`${i}`);
7+
continue loopend;
8+
}
9+
10+
loopend:
11+
console.log('end of loop');
12+
}
13+
14+
function bar() {
15+
continue loopend;
16+
}
17+
18+
19+
//// [issue30408.js]
20+
"use strict";
21+
function foo() {
22+
for (let i = 0; i < 10; i++) {
23+
console.log(`${i}`);
24+
continue loopend;
25+
}
26+
loopend: console.log('end of loop');
27+
}
28+
function bar() {
29+
continue loopend;
30+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//// [tests/cases/compiler/issue30408.ts] ////
2+
3+
=== issue30408.ts ===
4+
function foo() {
5+
>foo : Symbol(foo, Decl(issue30408.ts, 0, 0))
6+
7+
for (let i = 0; i < 10; i++) {
8+
>i : Symbol(i, Decl(issue30408.ts, 1, 12))
9+
>i : Symbol(i, Decl(issue30408.ts, 1, 12))
10+
>i : Symbol(i, Decl(issue30408.ts, 1, 12))
11+
12+
console.log(`${i}`);
13+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
14+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
15+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
16+
>i : Symbol(i, Decl(issue30408.ts, 1, 12))
17+
18+
continue loopend;
19+
}
20+
21+
loopend:
22+
console.log('end of loop');
23+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
24+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
25+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
26+
}
27+
28+
function bar() {
29+
>bar : Symbol(bar, Decl(issue30408.ts, 8, 1))
30+
31+
continue loopend;
32+
}
33+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//// [tests/cases/compiler/issue30408.ts] ////
2+
3+
=== issue30408.ts ===
4+
function foo() {
5+
>foo : () => void
6+
> : ^^^^^^^^^^
7+
8+
for (let i = 0; i < 10; i++) {
9+
>i : number
10+
> : ^^^^^^
11+
>0 : 0
12+
> : ^
13+
>i < 10 : boolean
14+
> : ^^^^^^^
15+
>i : number
16+
> : ^^^^^^
17+
>10 : 10
18+
> : ^^
19+
>i++ : number
20+
> : ^^^^^^
21+
>i : number
22+
> : ^^^^^^
23+
24+
console.log(`${i}`);
25+
>console.log(`${i}`) : void
26+
> : ^^^^
27+
>console.log : (...data: any[]) => void
28+
> : ^^^^ ^^ ^^^^^
29+
>console : Console
30+
> : ^^^^^^^
31+
>log : (...data: any[]) => void
32+
> : ^^^^ ^^ ^^^^^
33+
>`${i}` : string
34+
> : ^^^^^^
35+
>i : number
36+
> : ^^^^^^
37+
38+
continue loopend;
39+
>loopend : any
40+
> : ^^^
41+
}
42+
43+
loopend:
44+
>loopend : any
45+
> : ^^^
46+
47+
console.log('end of loop');
48+
>console.log('end of loop') : void
49+
> : ^^^^
50+
>console.log : (...data: any[]) => void
51+
> : ^^^^ ^^ ^^^^^
52+
>console : Console
53+
> : ^^^^^^^
54+
>log : (...data: any[]) => void
55+
> : ^^^^ ^^ ^^^^^
56+
>'end of loop' : "end of loop"
57+
> : ^^^^^^^^^^^^^
58+
}
59+
60+
function bar() {
61+
>bar : () => void
62+
> : ^^^^^^^^^^
63+
64+
continue loopend;
65+
>loopend : any
66+
> : ^^^
67+
}
68+

tests/baselines/reference/plainJSBinderErrors.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ plainJSBinderErrors.js(22,15): error TS1210: Code contained in a class is evalua
1212
plainJSBinderErrors.js(23,15): error TS1210: Code contained in a class is evaluated in JavaScript's strict mode which does not allow this use of 'arguments'. For more information, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode.
1313
plainJSBinderErrors.js(27,9): error TS1101: 'with' statements are not allowed in strict mode.
1414
plainJSBinderErrors.js(33,13): error TS1344: 'A label is not allowed here.
15-
plainJSBinderErrors.js(34,13): error TS1107: Jump target cannot cross function boundary.
15+
plainJSBinderErrors.js(34,13): error TS1116: A 'break' statement can only jump to a label of an enclosing statement.
1616
plainJSBinderErrors.js(39,7): error TS1215: Invalid use of 'eval'. Modules are automatically in strict mode.
1717
plainJSBinderErrors.js(40,7): error TS1215: Invalid use of 'arguments'. Modules are automatically in strict mode.
1818

@@ -83,7 +83,7 @@ plainJSBinderErrors.js(40,7): error TS1215: Invalid use of 'arguments'. Modules
8383
!!! error TS1344: 'A label is not allowed here.
8484
break label
8585
~~~~~~~~~~~
86-
!!! error TS1107: Jump target cannot cross function boundary.
86+
!!! error TS1116: A 'break' statement can only jump to a label of an enclosing statement.
8787
}
8888
return x
8989
}

tests/baselines/reference/plainJSGrammarErrors.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ plainJSGrammarErrors.js(167,12): error TS1197: Catch clause variable cannot have
9090
plainJSGrammarErrors.js(170,5): error TS1114: Duplicate label 'label'.
9191
plainJSGrammarErrors.js(179,13): error TS1107: Jump target cannot cross function boundary.
9292
plainJSGrammarErrors.js(187,13): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement.
93-
plainJSGrammarErrors.js(191,5): error TS1107: Jump target cannot cross function boundary.
93+
plainJSGrammarErrors.js(191,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement.
9494
plainJSGrammarErrors.js(194,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement.
9595
plainJSGrammarErrors.js(195,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement.
9696
plainJSGrammarErrors.js(197,1): error TS1105: A 'break' statement can only be used within an enclosing iteration or switch statement.
@@ -479,7 +479,7 @@ plainJSGrammarErrors.js(205,36): error TS1325: Argument of dynamic import cannot
479479
function jumpToLabelOnly(x) {
480480
break jumpToLabelOnly
481481
~~~~~~~~~~~~~~~~~~~~~
482-
!!! error TS1107: Jump target cannot cross function boundary.
482+
!!! error TS1116: A 'break' statement can only jump to a label of an enclosing statement.
483483
}
484484
for (;;) {
485485
break toplevel

tests/cases/compiler/issue30408.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
3+
function foo() {
4+
for (let i = 0; i < 10; i++) {
5+
console.log(`${i}`);
6+
continue loopend;
7+
}
8+
9+
loopend:
10+
console.log('end of loop');
11+
}
12+
13+
function bar() {
14+
continue loopend;
15+
}

0 commit comments

Comments
 (0)