diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8983725d206..a77da719e52 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8128,6 +8128,9 @@ module ts { } function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { + // Grammar checking + checkGrammarBreakOrContinueStatement(node); + // TODO: Check that target label is valid } @@ -10311,6 +10314,74 @@ module ts { } } + function isIterationStatement(node: Node, lookInLabeledStatements: boolean): boolean { + switch (node.kind) { + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + return true; + case SyntaxKind.LabeledStatement: + return lookInLabeledStatements && isIterationStatement((node).statement, lookInLabeledStatements); + } + + return false; + } + + function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean { + var current: Node = node; + while (current) { + if (isAnyFunction(current)) { + return grammarErrorOnNode(node, Diagnostics.Jump_target_cannot_cross_function_boundary); + } + + switch (current.kind) { + case SyntaxKind.LabeledStatement: + if (node.label && (current).label.text === node.label.text) { + // found matching label - verify that label usage is correct + // continue can only target labels that are on iteration statements + var isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement + && !isIterationStatement((current).statement, /*lookInLabeledStatement*/ true); + + if (isMisplacedContinueLabel) { + return grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + } + + return false; + } + break; + case SyntaxKind.SwitchStatement: + if (node.kind === SyntaxKind.BreakStatement && !node.label) { + // unlabeled break within switch statement - ok + return false; + } + break; + default: + if (isIterationStatement(current, /*lookInLabeledStatement*/ false) && !node.label) { + // unlabeled break or continue within iteration statement - ok + return false; + } + break; + } + + current = current.parent; + } + + if (node.label) { + var message = node.kind === SyntaxKind.BreakStatement + ? Diagnostics.A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement + : Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement; + + return grammarErrorOnNode(node, message) + } + else { + var message = node.kind === SyntaxKind.BreakStatement + ? Diagnostics.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement + : Diagnostics.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement; + return grammarErrorOnNode(node, message) + } + } + function hasParseDiagnostics(sourceFile: SourceFile): boolean { return sourceFile.parseDiagnostics.length > 0; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2763340551a..b2fbe11fcb5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4626,9 +4626,9 @@ module ts { function checkNode(node: Node, nodeKind: SyntaxKind): boolean { // Now do node specific checks. switch (nodeKind) { - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: - return checkBreakOrContinueStatement(node); + //case SyntaxKind.BreakStatement: + //case SyntaxKind.ContinueStatement: + //return checkBreakOrContinueStatement(node); //case SyntaxKind.CallExpression: //case SyntaxKind.NewExpression: //return checkCallOrNewExpression(node); diff --git a/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt b/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt index 65fd55b763b..6113009e598 100644 --- a/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidDoWhileBreakStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(4,1): error TS1105: A 'break' statement can only be used within an enclosing iteration or switch statement. tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(8,4): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. -tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(27,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(37,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. +tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt b/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt index e9643394d12..c89f9c01055 100644 --- a/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidDoWhileContinueStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(4,1): error TS1104: A 'continue' statement can only be used within an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(8,4): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. -tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(27,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(37,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. +tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/continueStatements/invalidDoWhileContinueStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidForBreakStatements.errors.txt b/tests/baselines/reference/invalidForBreakStatements.errors.txt index 50e4013c0ea..c63c97dcf69 100644 --- a/tests/baselines/reference/invalidForBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidForBreakStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(4,1): error TS1105: A 'break' statement can only be used within an enclosing iteration or switch statement. tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(8,9): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. -tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(27,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(36,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. +tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/breakStatements/invalidForBreakStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidForContinueStatements.errors.txt b/tests/baselines/reference/invalidForContinueStatements.errors.txt index 3af47370df1..459c2c5efa7 100644 --- a/tests/baselines/reference/invalidForContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidForContinueStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(4,1): error TS1104: A 'continue' statement can only be used within an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(8,9): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. -tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(27,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(36,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. +tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/continueStatements/invalidForContinueStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidForInBreakStatements.errors.txt b/tests/baselines/reference/invalidForInBreakStatements.errors.txt index d83304ab1c6..c12babd3a3a 100644 --- a/tests/baselines/reference/invalidForInBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidForInBreakStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(4,1): error TS1105: A 'break' statement can only be used within an enclosing iteration or switch statement. tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(8,19): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. -tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(27,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(37,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. +tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/breakStatements/invalidForInBreakStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidForInContinueStatements.errors.txt b/tests/baselines/reference/invalidForInContinueStatements.errors.txt index 7353a22d9cd..ebd96fd6e46 100644 --- a/tests/baselines/reference/invalidForInContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidForInContinueStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(4,1): error TS1104: A 'continue' statement can only be used within an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(8,19): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. -tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(27,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(37,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. +tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/continueStatements/invalidForInContinueStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidWhileBreakStatements.errors.txt b/tests/baselines/reference/invalidWhileBreakStatements.errors.txt index 54adc2856d7..1ed29772d7b 100644 --- a/tests/baselines/reference/invalidWhileBreakStatements.errors.txt +++ b/tests/baselines/reference/invalidWhileBreakStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(4,1): error TS1105: A 'break' statement can only be used within an enclosing iteration or switch statement. tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(8,14): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. -tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(27,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(37,5): error TS1116: A 'break' statement can only jump to a label of an enclosing statement. +tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/breakStatements/invalidWhileBreakStatements.ts (6 errors) ==== diff --git a/tests/baselines/reference/invalidWhileContinueStatements.errors.txt b/tests/baselines/reference/invalidWhileContinueStatements.errors.txt index 462b244efd4..ac658dbc944 100644 --- a/tests/baselines/reference/invalidWhileContinueStatements.errors.txt +++ b/tests/baselines/reference/invalidWhileContinueStatements.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(4,1): error TS1104: A 'continue' statement can only be used within an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(8,14): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. -tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. -tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(27,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(37,5): error TS1115: A 'continue' statement can only jump to a label of an enclosing iteration statement. +tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(14,9): error TS1107: Jump target cannot cross function boundary. +tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts(21,9): error TS1107: Jump target cannot cross function boundary. ==== tests/cases/conformance/statements/continueStatements/invalidWhileContinueStatements.ts (6 errors) ====