diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1cc293266605b..fe05b5c97a03c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -965,9 +965,6 @@ namespace ts { } function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode { - if (!isNarrowingExpression(switchStatement.expression)) { - return antecedent; - } setFlowNodeReferenced(antecedent); return flowNodeCreated({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd }); } @@ -1323,6 +1320,7 @@ namespace ts { const savedSubtreeTransformFlags = subtreeTransformFlags; subtreeTransformFlags = 0; const clauses = node.clauses; + const isNarrowingSwitch = isNarrowingExpression(node.parent.expression); let fallthroughFlow = unreachableFlow; for (let i = 0; i < clauses.length; i++) { const clauseStart = i; @@ -1331,7 +1329,7 @@ namespace ts { i++; } const preCaseLabel = createBranchLabel(); - addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1)); + addAntecedent(preCaseLabel, isNarrowingSwitch ? createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1) : preSwitchCaseFlow!); addAntecedent(preCaseLabel, fallthroughFlow); currentFlow = finishFlowLabel(preCaseLabel); const clause = clauses[i]; diff --git a/tests/baselines/reference/exhaustiveSwitchStatements1.errors.txt b/tests/baselines/reference/exhaustiveSwitchStatements1.errors.txt index 4a54518413d18..d6be1215e164d 100644 --- a/tests/baselines/reference/exhaustiveSwitchStatements1.errors.txt +++ b/tests/baselines/reference/exhaustiveSwitchStatements1.errors.txt @@ -199,4 +199,17 @@ tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts(7,9): error T } return x; } + + // Repro from #34661 + + enum Animal { DOG, CAT } + + declare const zoo: { animal: Animal } | undefined; + + function expression(): Animal { + switch (zoo?.animal ?? Animal.DOG) { + case Animal.DOG: return Animal.DOG + case Animal.CAT: return Animal.CAT + } + } \ No newline at end of file diff --git a/tests/baselines/reference/exhaustiveSwitchStatements1.js b/tests/baselines/reference/exhaustiveSwitchStatements1.js index a39db3b8101d5..b7da0e008b303 100644 --- a/tests/baselines/reference/exhaustiveSwitchStatements1.js +++ b/tests/baselines/reference/exhaustiveSwitchStatements1.js @@ -194,6 +194,19 @@ function test4(value: 1 | 2) { } return x; } + +// Repro from #34661 + +enum Animal { DOG, CAT } + +declare const zoo: { animal: Animal } | undefined; + +function expression(): Animal { + switch (zoo?.animal ?? Animal.DOG) { + case Animal.DOG: return Animal.DOG + case Animal.CAT: return Animal.CAT + } +} //// [exhaustiveSwitchStatements1.js] @@ -379,6 +392,19 @@ function test4(value) { } return x; } +// Repro from #34661 +var Animal; +(function (Animal) { + Animal[Animal["DOG"] = 0] = "DOG"; + Animal[Animal["CAT"] = 1] = "CAT"; +})(Animal || (Animal = {})); +function expression() { + var _a, _b; + switch ((_b = (_a = zoo) === null || _a === void 0 ? void 0 : _a.animal, (_b !== null && _b !== void 0 ? _b : Animal.DOG))) { + case Animal.DOG: return Animal.DOG; + case Animal.CAT: return Animal.CAT; + } +} //// [exhaustiveSwitchStatements1.d.ts] @@ -435,3 +461,11 @@ declare type Shape2 = Square2 | Circle2; declare function withDefault(s1: Shape2, s2: Shape2): string; declare function withoutDefault(s1: Shape2, s2: Shape2): string; declare function test4(value: 1 | 2): string; +declare enum Animal { + DOG = 0, + CAT = 1 +} +declare const zoo: { + animal: Animal; +} | undefined; +declare function expression(): Animal; diff --git a/tests/baselines/reference/exhaustiveSwitchStatements1.symbols b/tests/baselines/reference/exhaustiveSwitchStatements1.symbols index 8beb391188359..3797f342228b6 100644 --- a/tests/baselines/reference/exhaustiveSwitchStatements1.symbols +++ b/tests/baselines/reference/exhaustiveSwitchStatements1.symbols @@ -501,3 +501,45 @@ function test4(value: 1 | 2) { >x : Symbol(x, Decl(exhaustiveSwitchStatements1.ts, 188, 7)) } +// Repro from #34661 + +enum Animal { DOG, CAT } +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) +>DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) +>CAT : Symbol(Animal.CAT, Decl(exhaustiveSwitchStatements1.ts, 198, 18)) + +declare const zoo: { animal: Animal } | undefined; +>zoo : Symbol(zoo, Decl(exhaustiveSwitchStatements1.ts, 200, 13)) +>animal : Symbol(animal, Decl(exhaustiveSwitchStatements1.ts, 200, 20)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) + +function expression(): Animal { +>expression : Symbol(expression, Decl(exhaustiveSwitchStatements1.ts, 200, 50)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) + + switch (zoo?.animal ?? Animal.DOG) { +>zoo?.animal : Symbol(animal, Decl(exhaustiveSwitchStatements1.ts, 200, 20)) +>zoo : Symbol(zoo, Decl(exhaustiveSwitchStatements1.ts, 200, 13)) +>animal : Symbol(animal, Decl(exhaustiveSwitchStatements1.ts, 200, 20)) +>Animal.DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) +>DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) + + case Animal.DOG: return Animal.DOG +>Animal.DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) +>DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) +>Animal.DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) +>DOG : Symbol(Animal.DOG, Decl(exhaustiveSwitchStatements1.ts, 198, 13)) + + case Animal.CAT: return Animal.CAT +>Animal.CAT : Symbol(Animal.CAT, Decl(exhaustiveSwitchStatements1.ts, 198, 18)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) +>CAT : Symbol(Animal.CAT, Decl(exhaustiveSwitchStatements1.ts, 198, 18)) +>Animal.CAT : Symbol(Animal.CAT, Decl(exhaustiveSwitchStatements1.ts, 198, 18)) +>Animal : Symbol(Animal, Decl(exhaustiveSwitchStatements1.ts, 194, 1)) +>CAT : Symbol(Animal.CAT, Decl(exhaustiveSwitchStatements1.ts, 198, 18)) + } +} + diff --git a/tests/baselines/reference/exhaustiveSwitchStatements1.types b/tests/baselines/reference/exhaustiveSwitchStatements1.types index 04a9bf531ce9c..0eb327c9d6de8 100644 --- a/tests/baselines/reference/exhaustiveSwitchStatements1.types +++ b/tests/baselines/reference/exhaustiveSwitchStatements1.types @@ -593,3 +593,44 @@ function test4(value: 1 | 2) { >x : string } +// Repro from #34661 + +enum Animal { DOG, CAT } +>Animal : Animal +>DOG : Animal.DOG +>CAT : Animal.CAT + +declare const zoo: { animal: Animal } | undefined; +>zoo : { animal: Animal; } | undefined +>animal : Animal + +function expression(): Animal { +>expression : () => Animal + + switch (zoo?.animal ?? Animal.DOG) { +>zoo?.animal ?? Animal.DOG : Animal +>zoo?.animal : Animal | undefined +>zoo : { animal: Animal; } | undefined +>animal : Animal | undefined +>Animal.DOG : Animal.DOG +>Animal : typeof Animal +>DOG : Animal.DOG + + case Animal.DOG: return Animal.DOG +>Animal.DOG : Animal.DOG +>Animal : typeof Animal +>DOG : Animal.DOG +>Animal.DOG : Animal.DOG +>Animal : typeof Animal +>DOG : Animal.DOG + + case Animal.CAT: return Animal.CAT +>Animal.CAT : Animal.CAT +>Animal : typeof Animal +>CAT : Animal.CAT +>Animal.CAT : Animal.CAT +>Animal : typeof Animal +>CAT : Animal.CAT + } +} + diff --git a/tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts b/tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts index 9fd0f608ddb3f..72de718411f54 100644 --- a/tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts +++ b/tests/cases/conformance/controlFlow/exhaustiveSwitchStatements1.ts @@ -197,3 +197,16 @@ function test4(value: 1 | 2) { } return x; } + +// Repro from #34661 + +enum Animal { DOG, CAT } + +declare const zoo: { animal: Animal } | undefined; + +function expression(): Animal { + switch (zoo?.animal ?? Animal.DOG) { + case Animal.DOG: return Animal.DOG + case Animal.CAT: return Animal.CAT + } +}