Skip to content

Commit 6a9055c

Browse files
authored
Merge pull request #27612 from Microsoft/fixSwitchCaseControlFlow
Fix switch case control flow
2 parents b185784 + 7bdc361 commit 6a9055c

7 files changed

+286
-5
lines changed

src/compiler/binder.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,6 @@ namespace ts {
11811181
}
11821182
const preCaseLabel = createBranchLabel();
11831183
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1));
1184-
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1));
11851184
addAntecedent(preCaseLabel, fallthroughFlow);
11861185
currentFlow = finishFlowLabel(preCaseLabel);
11871186
const clause = clauses[i];

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14972,9 +14972,12 @@ namespace ts {
1497214972
}
1497314973

1497414974
function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType {
14975+
const expr = flow.switchStatement.expression;
14976+
if (containsMatchingReferenceDiscriminant(reference, expr)) {
14977+
return declaredType;
14978+
}
1497514979
const flowType = getTypeAtFlowNode(flow.antecedent);
1497614980
let type = getTypeFromFlowType(flowType);
14977-
const expr = flow.switchStatement.expression;
1497814981
if (isMatchingReference(reference, expr)) {
1497914982
type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
1498014983
}

tests/baselines/reference/discriminantPropertyCheck.errors.txt

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,37 @@ tests/cases/compiler/discriminantPropertyCheck.ts(65,9): error TS2532: Object is
7373
~~~~~
7474
!!! error TS2532: Object is possibly 'undefined'.
7575
}
76-
}
76+
}
77+
78+
// Repro from #27493
79+
80+
enum Types { Str = 1, Num = 2 }
81+
82+
type Instance = StrType | NumType;
83+
84+
interface StrType {
85+
type: Types.Str;
86+
value: string;
87+
length: number;
88+
}
89+
90+
interface NumType {
91+
type: Types.Num;
92+
value: number;
93+
}
94+
95+
function func2(inst: Instance) {
96+
while (true) {
97+
switch (inst.type) {
98+
case Types.Str: {
99+
inst.value.length;
100+
break;
101+
}
102+
case Types.Num: {
103+
inst.value.toExponential;
104+
break;
105+
}
106+
}
107+
}
108+
}
109+

tests/baselines/reference/discriminantPropertyCheck.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,40 @@ function foo6(x: Item) {
6565
if (x.foo !== undefined && x.qux) {
6666
x.foo.length; // Error, intervening discriminant guard
6767
}
68-
}
68+
}
69+
70+
// Repro from #27493
71+
72+
enum Types { Str = 1, Num = 2 }
73+
74+
type Instance = StrType | NumType;
75+
76+
interface StrType {
77+
type: Types.Str;
78+
value: string;
79+
length: number;
80+
}
81+
82+
interface NumType {
83+
type: Types.Num;
84+
value: number;
85+
}
86+
87+
function func2(inst: Instance) {
88+
while (true) {
89+
switch (inst.type) {
90+
case Types.Str: {
91+
inst.value.length;
92+
break;
93+
}
94+
case Types.Num: {
95+
inst.value.toExponential;
96+
break;
97+
}
98+
}
99+
}
100+
}
101+
69102

70103
//// [discriminantPropertyCheck.js]
71104
function goo1(x) {
@@ -108,3 +141,23 @@ function foo6(x) {
108141
x.foo.length; // Error, intervening discriminant guard
109142
}
110143
}
144+
// Repro from #27493
145+
var Types;
146+
(function (Types) {
147+
Types[Types["Str"] = 1] = "Str";
148+
Types[Types["Num"] = 2] = "Num";
149+
})(Types || (Types = {}));
150+
function func2(inst) {
151+
while (true) {
152+
switch (inst.type) {
153+
case Types.Str: {
154+
inst.value.length;
155+
break;
156+
}
157+
case Types.Num: {
158+
inst.value.toExponential;
159+
break;
160+
}
161+
}
162+
}
163+
}

tests/baselines/reference/discriminantPropertyCheck.symbols

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,86 @@ function foo6(x: Item) {
228228
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
229229
}
230230
}
231+
232+
// Repro from #27493
233+
234+
enum Types { Str = 1, Num = 2 }
235+
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
236+
>Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
237+
>Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
238+
239+
type Instance = StrType | NumType;
240+
>Instance : Symbol(Instance, Decl(discriminantPropertyCheck.ts, 70, 31))
241+
>StrType : Symbol(StrType, Decl(discriminantPropertyCheck.ts, 72, 34))
242+
>NumType : Symbol(NumType, Decl(discriminantPropertyCheck.ts, 78, 1))
243+
244+
interface StrType {
245+
>StrType : Symbol(StrType, Decl(discriminantPropertyCheck.ts, 72, 34))
246+
247+
type: Types.Str;
248+
>type : Symbol(StrType.type, Decl(discriminantPropertyCheck.ts, 74, 19))
249+
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
250+
>Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
251+
252+
value: string;
253+
>value : Symbol(StrType.value, Decl(discriminantPropertyCheck.ts, 75, 20))
254+
255+
length: number;
256+
>length : Symbol(StrType.length, Decl(discriminantPropertyCheck.ts, 76, 18))
257+
}
258+
259+
interface NumType {
260+
>NumType : Symbol(NumType, Decl(discriminantPropertyCheck.ts, 78, 1))
261+
262+
type: Types.Num;
263+
>type : Symbol(NumType.type, Decl(discriminantPropertyCheck.ts, 80, 19))
264+
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
265+
>Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
266+
267+
value: number;
268+
>value : Symbol(NumType.value, Decl(discriminantPropertyCheck.ts, 81, 20))
269+
}
270+
271+
function func2(inst: Instance) {
272+
>func2 : Symbol(func2, Decl(discriminantPropertyCheck.ts, 83, 1))
273+
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
274+
>Instance : Symbol(Instance, Decl(discriminantPropertyCheck.ts, 70, 31))
275+
276+
while (true) {
277+
switch (inst.type) {
278+
>inst.type : Symbol(type, Decl(discriminantPropertyCheck.ts, 74, 19), Decl(discriminantPropertyCheck.ts, 80, 19))
279+
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
280+
>type : Symbol(type, Decl(discriminantPropertyCheck.ts, 74, 19), Decl(discriminantPropertyCheck.ts, 80, 19))
281+
282+
case Types.Str: {
283+
>Types.Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
284+
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
285+
>Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
286+
287+
inst.value.length;
288+
>inst.value.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
289+
>inst.value : Symbol(StrType.value, Decl(discriminantPropertyCheck.ts, 75, 20))
290+
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
291+
>value : Symbol(StrType.value, Decl(discriminantPropertyCheck.ts, 75, 20))
292+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
293+
294+
break;
295+
}
296+
case Types.Num: {
297+
>Types.Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
298+
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
299+
>Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
300+
301+
inst.value.toExponential;
302+
>inst.value.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
303+
>inst.value : Symbol(NumType.value, Decl(discriminantPropertyCheck.ts, 81, 20))
304+
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
305+
>value : Symbol(NumType.value, Decl(discriminantPropertyCheck.ts, 81, 20))
306+
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
307+
308+
break;
309+
}
310+
}
311+
}
312+
}
313+

tests/baselines/reference/discriminantPropertyCheck.types

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,81 @@ function foo6(x: Item) {
232232
>length : number
233233
}
234234
}
235+
236+
// Repro from #27493
237+
238+
enum Types { Str = 1, Num = 2 }
239+
>Types : Types
240+
>Str : Types.Str
241+
>1 : 1
242+
>Num : Types.Num
243+
>2 : 2
244+
245+
type Instance = StrType | NumType;
246+
>Instance : Instance
247+
248+
interface StrType {
249+
type: Types.Str;
250+
>type : Types.Str
251+
>Types : any
252+
253+
value: string;
254+
>value : string
255+
256+
length: number;
257+
>length : number
258+
}
259+
260+
interface NumType {
261+
type: Types.Num;
262+
>type : Types.Num
263+
>Types : any
264+
265+
value: number;
266+
>value : number
267+
}
268+
269+
function func2(inst: Instance) {
270+
>func2 : (inst: Instance) => void
271+
>inst : Instance
272+
273+
while (true) {
274+
>true : true
275+
276+
switch (inst.type) {
277+
>inst.type : Types
278+
>inst : Instance
279+
>type : Types
280+
281+
case Types.Str: {
282+
>Types.Str : Types.Str
283+
>Types : typeof Types
284+
>Str : Types.Str
285+
286+
inst.value.length;
287+
>inst.value.length : number
288+
>inst.value : string
289+
>inst : StrType
290+
>value : string
291+
>length : number
292+
293+
break;
294+
}
295+
case Types.Num: {
296+
>Types.Num : Types.Num
297+
>Types : typeof Types
298+
>Num : Types.Num
299+
300+
inst.value.toExponential;
301+
>inst.value.toExponential : (fractionDigits?: number | undefined) => string
302+
>inst.value : number
303+
>inst : NumType
304+
>value : number
305+
>toExponential : (fractionDigits?: number | undefined) => string
306+
307+
break;
308+
}
309+
}
310+
}
311+
}
312+

tests/cases/compiler/discriminantPropertyCheck.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,36 @@ function foo6(x: Item) {
6666
if (x.foo !== undefined && x.qux) {
6767
x.foo.length; // Error, intervening discriminant guard
6868
}
69-
}
69+
}
70+
71+
// Repro from #27493
72+
73+
enum Types { Str = 1, Num = 2 }
74+
75+
type Instance = StrType | NumType;
76+
77+
interface StrType {
78+
type: Types.Str;
79+
value: string;
80+
length: number;
81+
}
82+
83+
interface NumType {
84+
type: Types.Num;
85+
value: number;
86+
}
87+
88+
function func2(inst: Instance) {
89+
while (true) {
90+
switch (inst.type) {
91+
case Types.Str: {
92+
inst.value.length;
93+
break;
94+
}
95+
case Types.Num: {
96+
inst.value.toExponential;
97+
break;
98+
}
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)