mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #34212 from microsoft/fix34021
Fix control flow analysis for --noFallthroughCasesInSwitch
This commit is contained in:
@@ -1341,7 +1341,7 @@ namespace ts {
|
||||
bind(clause);
|
||||
fallthroughFlow = currentFlow;
|
||||
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
|
||||
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
|
||||
clause.fallthroughFlowNode = currentFlow;
|
||||
}
|
||||
}
|
||||
clauses.transformFlags = subtreeTransformFlags | TransformFlags.HasComputedFlags;
|
||||
|
||||
@@ -31054,10 +31054,7 @@ namespace ts {
|
||||
firstDefaultClause = clause;
|
||||
}
|
||||
else {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
const start = skipTrivia(sourceFile.text, clause.pos);
|
||||
const end = clause.statements.length > 0 ? clause.statements[0].pos : clause.end;
|
||||
grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement);
|
||||
grammarErrorOnNode(clause, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement);
|
||||
hasDuplicateDefaultClause = true;
|
||||
}
|
||||
}
|
||||
@@ -31079,6 +31076,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
forEach(clause.statements, checkSourceElement);
|
||||
if (compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode && isReachableFlowNode(clause.fallthroughFlowNode)) {
|
||||
error(clause, Diagnostics.Fallthrough_case_in_switch);
|
||||
}
|
||||
});
|
||||
if (node.caseBlock.locals) {
|
||||
registerForUnusedIdentifiersCheck(node.caseBlock);
|
||||
|
||||
@@ -2250,12 +2250,14 @@ namespace ts {
|
||||
parent: CaseBlock;
|
||||
expression: Expression;
|
||||
statements: NodeArray<Statement>;
|
||||
/* @internal */ fallthroughFlowNode?: FlowNode;
|
||||
}
|
||||
|
||||
export interface DefaultClause extends Node {
|
||||
kind: SyntaxKind.DefaultClause;
|
||||
parent: CaseBlock;
|
||||
statements: NodeArray<Statement>;
|
||||
/* @internal */ fallthroughFlowNode?: FlowNode;
|
||||
}
|
||||
|
||||
export type CaseOrDefaultClause = CaseClause | DefaultClause;
|
||||
|
||||
@@ -961,6 +961,11 @@ namespace ts {
|
||||
break;
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return getErrorSpanForArrowFunction(sourceFile, <ArrowFunction>node);
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
const start = skipTrivia(sourceFile.text, (<CaseOrDefaultClause>node).pos);
|
||||
const end = (<CaseOrDefaultClause>node).statements.length > 0 ? (<CaseOrDefaultClause>node).statements[0].pos : (<CaseOrDefaultClause>node).end;
|
||||
return createTextSpanFromBounds(start, end);
|
||||
}
|
||||
|
||||
if (errorNode === undefined) {
|
||||
|
||||
@@ -11,7 +11,7 @@ tests/cases/compiler/fallFromLastCase2.ts(21,9): error TS7029: Fallthrough case
|
||||
use("1");
|
||||
break;
|
||||
case 2:
|
||||
~~~~
|
||||
~~~~~~~
|
||||
!!! error TS7029: Fallthrough case in switch.
|
||||
use("2");
|
||||
case 3:
|
||||
@@ -26,7 +26,7 @@ tests/cases/compiler/fallFromLastCase2.ts(21,9): error TS7029: Fallthrough case
|
||||
use("1");
|
||||
break;
|
||||
default:
|
||||
~~~~~~~
|
||||
~~~~~~~~
|
||||
!!! error TS7029: Fallthrough case in switch.
|
||||
use("2");
|
||||
case 2:
|
||||
|
||||
@@ -7,7 +7,7 @@ tests/cases/compiler/a.js(19,1): error TS7028: Unused label.
|
||||
function foo(a, b) {
|
||||
switch (a) {
|
||||
case 10:
|
||||
~~~~
|
||||
~~~~~~~~
|
||||
!!! error TS7029: Fallthrough case in switch.
|
||||
if (b) {
|
||||
return b;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
tests/cases/compiler/reachabilityChecks4.ts(6,9): error TS7029: Fallthrough case in switch.
|
||||
tests/cases/compiler/reachabilityChecks4.ts(22,9): error TS7029: Fallthrough case in switch.
|
||||
|
||||
|
||||
==== tests/cases/compiler/reachabilityChecks4.ts (1 errors) ====
|
||||
==== tests/cases/compiler/reachabilityChecks4.ts (2 errors) ====
|
||||
function foo(x, y) {
|
||||
switch (x) {
|
||||
case 1:
|
||||
case 2:
|
||||
return 1;
|
||||
case 3:
|
||||
~~~~
|
||||
~~~~~~~
|
||||
!!! error TS7029: Fallthrough case in switch.
|
||||
if (y) {
|
||||
return 2;
|
||||
@@ -16,4 +17,58 @@ tests/cases/compiler/reachabilityChecks4.ts(6,9): error TS7029: Fallthrough case
|
||||
case 4:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare function noop(): void;
|
||||
declare function fail(): never;
|
||||
|
||||
function f1(x: 0 | 1 | 2) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
fail();
|
||||
case 1:
|
||||
~~~~~~~
|
||||
!!! error TS7029: Fallthrough case in switch.
|
||||
noop();
|
||||
case 2:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #34021
|
||||
|
||||
type Behavior = 'SLIDE' | 'SLIDE_OUT'
|
||||
type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
|
||||
|
||||
interface Transition {
|
||||
behavior: Behavior
|
||||
direction: Direction
|
||||
}
|
||||
|
||||
function f2(transition: Transition): any {
|
||||
switch (transition.behavior) {
|
||||
case 'SLIDE':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
case 'SLIDE_OUT':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,59 @@ function foo(x, y) {
|
||||
case 4:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare function noop(): void;
|
||||
declare function fail(): never;
|
||||
|
||||
function f1(x: 0 | 1 | 2) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
fail();
|
||||
case 1:
|
||||
noop();
|
||||
case 2:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #34021
|
||||
|
||||
type Behavior = 'SLIDE' | 'SLIDE_OUT'
|
||||
type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
|
||||
|
||||
interface Transition {
|
||||
behavior: Behavior
|
||||
direction: Direction
|
||||
}
|
||||
|
||||
function f2(transition: Transition): any {
|
||||
switch (transition.behavior) {
|
||||
case 'SLIDE':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
case 'SLIDE_OUT':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [reachabilityChecks4.js]
|
||||
function foo(x, y) {
|
||||
@@ -27,3 +79,39 @@ function foo(x, y) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
function f1(x) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
fail();
|
||||
case 1:
|
||||
noop();
|
||||
case 2:
|
||||
return;
|
||||
}
|
||||
}
|
||||
function f2(transition) {
|
||||
switch (transition.behavior) {
|
||||
case 'SLIDE':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return [];
|
||||
case 'RIGHT':
|
||||
return [];
|
||||
case 'TOP':
|
||||
return [];
|
||||
case 'BOTTOM':
|
||||
return [];
|
||||
}
|
||||
case 'SLIDE_OUT':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return [];
|
||||
case 'RIGHT':
|
||||
return [];
|
||||
case 'TOP':
|
||||
return [];
|
||||
case 'BOTTOM':
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,3 +20,93 @@ function foo(x, y) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
declare function noop(): void;
|
||||
>noop : Symbol(noop, Decl(reachabilityChecks4.ts, 12, 1))
|
||||
|
||||
declare function fail(): never;
|
||||
>fail : Symbol(fail, Decl(reachabilityChecks4.ts, 14, 30))
|
||||
|
||||
function f1(x: 0 | 1 | 2) {
|
||||
>f1 : Symbol(f1, Decl(reachabilityChecks4.ts, 15, 31))
|
||||
>x : Symbol(x, Decl(reachabilityChecks4.ts, 17, 12))
|
||||
|
||||
switch (x) {
|
||||
>x : Symbol(x, Decl(reachabilityChecks4.ts, 17, 12))
|
||||
|
||||
case 0:
|
||||
fail();
|
||||
>fail : Symbol(fail, Decl(reachabilityChecks4.ts, 14, 30))
|
||||
|
||||
case 1:
|
||||
noop();
|
||||
>noop : Symbol(noop, Decl(reachabilityChecks4.ts, 12, 1))
|
||||
|
||||
case 2:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #34021
|
||||
|
||||
type Behavior = 'SLIDE' | 'SLIDE_OUT'
|
||||
>Behavior : Symbol(Behavior, Decl(reachabilityChecks4.ts, 26, 1))
|
||||
|
||||
type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
|
||||
>Direction : Symbol(Direction, Decl(reachabilityChecks4.ts, 30, 37))
|
||||
|
||||
interface Transition {
|
||||
>Transition : Symbol(Transition, Decl(reachabilityChecks4.ts, 31, 52))
|
||||
|
||||
behavior: Behavior
|
||||
>behavior : Symbol(Transition.behavior, Decl(reachabilityChecks4.ts, 33, 22))
|
||||
>Behavior : Symbol(Behavior, Decl(reachabilityChecks4.ts, 26, 1))
|
||||
|
||||
direction: Direction
|
||||
>direction : Symbol(Transition.direction, Decl(reachabilityChecks4.ts, 34, 20))
|
||||
>Direction : Symbol(Direction, Decl(reachabilityChecks4.ts, 30, 37))
|
||||
}
|
||||
|
||||
function f2(transition: Transition): any {
|
||||
>f2 : Symbol(f2, Decl(reachabilityChecks4.ts, 36, 1))
|
||||
>transition : Symbol(transition, Decl(reachabilityChecks4.ts, 38, 12))
|
||||
>Transition : Symbol(Transition, Decl(reachabilityChecks4.ts, 31, 52))
|
||||
|
||||
switch (transition.behavior) {
|
||||
>transition.behavior : Symbol(Transition.behavior, Decl(reachabilityChecks4.ts, 33, 22))
|
||||
>transition : Symbol(transition, Decl(reachabilityChecks4.ts, 38, 12))
|
||||
>behavior : Symbol(Transition.behavior, Decl(reachabilityChecks4.ts, 33, 22))
|
||||
|
||||
case 'SLIDE':
|
||||
switch (transition.direction) {
|
||||
>transition.direction : Symbol(Transition.direction, Decl(reachabilityChecks4.ts, 34, 20))
|
||||
>transition : Symbol(transition, Decl(reachabilityChecks4.ts, 38, 12))
|
||||
>direction : Symbol(Transition.direction, Decl(reachabilityChecks4.ts, 34, 20))
|
||||
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
case 'SLIDE_OUT':
|
||||
switch (transition.direction) {
|
||||
>transition.direction : Symbol(Transition.direction, Decl(reachabilityChecks4.ts, 34, 20))
|
||||
>transition : Symbol(transition, Decl(reachabilityChecks4.ts, 38, 12))
|
||||
>direction : Symbol(Transition.direction, Decl(reachabilityChecks4.ts, 34, 20))
|
||||
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,3 +32,130 @@ function foo(x, y) {
|
||||
>3 : 3
|
||||
}
|
||||
}
|
||||
|
||||
declare function noop(): void;
|
||||
>noop : () => void
|
||||
|
||||
declare function fail(): never;
|
||||
>fail : () => never
|
||||
|
||||
function f1(x: 0 | 1 | 2) {
|
||||
>f1 : (x: 0 | 1 | 2) => void
|
||||
>x : 0 | 1 | 2
|
||||
|
||||
switch (x) {
|
||||
>x : 0 | 1 | 2
|
||||
|
||||
case 0:
|
||||
>0 : 0
|
||||
|
||||
fail();
|
||||
>fail() : never
|
||||
>fail : () => never
|
||||
|
||||
case 1:
|
||||
>1 : 1
|
||||
|
||||
noop();
|
||||
>noop() : void
|
||||
>noop : () => void
|
||||
|
||||
case 2:
|
||||
>2 : 2
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #34021
|
||||
|
||||
type Behavior = 'SLIDE' | 'SLIDE_OUT'
|
||||
>Behavior : Behavior
|
||||
|
||||
type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
|
||||
>Direction : Direction
|
||||
|
||||
interface Transition {
|
||||
behavior: Behavior
|
||||
>behavior : Behavior
|
||||
|
||||
direction: Direction
|
||||
>direction : Direction
|
||||
}
|
||||
|
||||
function f2(transition: Transition): any {
|
||||
>f2 : (transition: Transition) => any
|
||||
>transition : Transition
|
||||
|
||||
switch (transition.behavior) {
|
||||
>transition.behavior : Behavior
|
||||
>transition : Transition
|
||||
>behavior : Behavior
|
||||
|
||||
case 'SLIDE':
|
||||
>'SLIDE' : "SLIDE"
|
||||
|
||||
switch (transition.direction) {
|
||||
>transition.direction : Direction
|
||||
>transition : Transition
|
||||
>direction : Direction
|
||||
|
||||
case 'LEFT':
|
||||
>'LEFT' : "LEFT"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
|
||||
case 'RIGHT':
|
||||
>'RIGHT' : "RIGHT"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
|
||||
case 'TOP':
|
||||
>'TOP' : "TOP"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
|
||||
case 'BOTTOM':
|
||||
>'BOTTOM' : "BOTTOM"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
}
|
||||
case 'SLIDE_OUT':
|
||||
>'SLIDE_OUT' : "SLIDE_OUT"
|
||||
|
||||
switch (transition.direction) {
|
||||
>transition.direction : Direction
|
||||
>transition : Transition
|
||||
>direction : Direction
|
||||
|
||||
case 'LEFT':
|
||||
>'LEFT' : "LEFT"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
|
||||
case 'RIGHT':
|
||||
>'RIGHT' : "RIGHT"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
|
||||
case 'TOP':
|
||||
>'TOP' : "TOP"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
|
||||
case 'BOTTOM':
|
||||
>'BOTTOM' : "BOTTOM"
|
||||
|
||||
return []
|
||||
>[] : undefined[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,4 +12,55 @@ function foo(x, y) {
|
||||
case 4:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare function noop(): void;
|
||||
declare function fail(): never;
|
||||
|
||||
function f1(x: 0 | 1 | 2) {
|
||||
switch (x) {
|
||||
case 0:
|
||||
fail();
|
||||
case 1:
|
||||
noop();
|
||||
case 2:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #34021
|
||||
|
||||
type Behavior = 'SLIDE' | 'SLIDE_OUT'
|
||||
type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
|
||||
|
||||
interface Transition {
|
||||
behavior: Behavior
|
||||
direction: Direction
|
||||
}
|
||||
|
||||
function f2(transition: Transition): any {
|
||||
switch (transition.behavior) {
|
||||
case 'SLIDE':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
case 'SLIDE_OUT':
|
||||
switch (transition.direction) {
|
||||
case 'LEFT':
|
||||
return []
|
||||
case 'RIGHT':
|
||||
return []
|
||||
case 'TOP':
|
||||
return []
|
||||
case 'BOTTOM':
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user