Merge pull request #27612 from Microsoft/fixSwitchCaseControlFlow

Fix switch case control flow
This commit is contained in:
Anders Hejlsberg 2018-10-08 11:12:24 -07:00 committed by GitHub
commit 6a9055ca0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 286 additions and 5 deletions

View File

@ -1181,7 +1181,6 @@ namespace ts {
}
const preCaseLabel = createBranchLabel();
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1));
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1));
addAntecedent(preCaseLabel, fallthroughFlow);
currentFlow = finishFlowLabel(preCaseLabel);
const clause = clauses[i];

View File

@ -14972,9 +14972,12 @@ namespace ts {
}
function getTypeAtSwitchClause(flow: FlowSwitchClause): FlowType {
const expr = flow.switchStatement.expression;
if (containsMatchingReferenceDiscriminant(reference, expr)) {
return declaredType;
}
const flowType = getTypeAtFlowNode(flow.antecedent);
let type = getTypeFromFlowType(flowType);
const expr = flow.switchStatement.expression;
if (isMatchingReference(reference, expr)) {
type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
}

View File

@ -73,4 +73,37 @@ tests/cases/compiler/discriminantPropertyCheck.ts(65,9): error TS2532: Object is
~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
}
}
// Repro from #27493
enum Types { Str = 1, Num = 2 }
type Instance = StrType | NumType;
interface StrType {
type: Types.Str;
value: string;
length: number;
}
interface NumType {
type: Types.Num;
value: number;
}
function func2(inst: Instance) {
while (true) {
switch (inst.type) {
case Types.Str: {
inst.value.length;
break;
}
case Types.Num: {
inst.value.toExponential;
break;
}
}
}
}

View File

@ -65,7 +65,40 @@ function foo6(x: Item) {
if (x.foo !== undefined && x.qux) {
x.foo.length; // Error, intervening discriminant guard
}
}
}
// Repro from #27493
enum Types { Str = 1, Num = 2 }
type Instance = StrType | NumType;
interface StrType {
type: Types.Str;
value: string;
length: number;
}
interface NumType {
type: Types.Num;
value: number;
}
function func2(inst: Instance) {
while (true) {
switch (inst.type) {
case Types.Str: {
inst.value.length;
break;
}
case Types.Num: {
inst.value.toExponential;
break;
}
}
}
}
//// [discriminantPropertyCheck.js]
function goo1(x) {
@ -108,3 +141,23 @@ function foo6(x) {
x.foo.length; // Error, intervening discriminant guard
}
}
// Repro from #27493
var Types;
(function (Types) {
Types[Types["Str"] = 1] = "Str";
Types[Types["Num"] = 2] = "Num";
})(Types || (Types = {}));
function func2(inst) {
while (true) {
switch (inst.type) {
case Types.Str: {
inst.value.length;
break;
}
case Types.Num: {
inst.value.toExponential;
break;
}
}
}
}

View File

@ -228,3 +228,86 @@ function foo6(x: Item) {
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
}
}
// Repro from #27493
enum Types { Str = 1, Num = 2 }
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
>Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
>Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
type Instance = StrType | NumType;
>Instance : Symbol(Instance, Decl(discriminantPropertyCheck.ts, 70, 31))
>StrType : Symbol(StrType, Decl(discriminantPropertyCheck.ts, 72, 34))
>NumType : Symbol(NumType, Decl(discriminantPropertyCheck.ts, 78, 1))
interface StrType {
>StrType : Symbol(StrType, Decl(discriminantPropertyCheck.ts, 72, 34))
type: Types.Str;
>type : Symbol(StrType.type, Decl(discriminantPropertyCheck.ts, 74, 19))
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
>Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
value: string;
>value : Symbol(StrType.value, Decl(discriminantPropertyCheck.ts, 75, 20))
length: number;
>length : Symbol(StrType.length, Decl(discriminantPropertyCheck.ts, 76, 18))
}
interface NumType {
>NumType : Symbol(NumType, Decl(discriminantPropertyCheck.ts, 78, 1))
type: Types.Num;
>type : Symbol(NumType.type, Decl(discriminantPropertyCheck.ts, 80, 19))
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
>Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
value: number;
>value : Symbol(NumType.value, Decl(discriminantPropertyCheck.ts, 81, 20))
}
function func2(inst: Instance) {
>func2 : Symbol(func2, Decl(discriminantPropertyCheck.ts, 83, 1))
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
>Instance : Symbol(Instance, Decl(discriminantPropertyCheck.ts, 70, 31))
while (true) {
switch (inst.type) {
>inst.type : Symbol(type, Decl(discriminantPropertyCheck.ts, 74, 19), Decl(discriminantPropertyCheck.ts, 80, 19))
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
>type : Symbol(type, Decl(discriminantPropertyCheck.ts, 74, 19), Decl(discriminantPropertyCheck.ts, 80, 19))
case Types.Str: {
>Types.Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
>Str : Symbol(Types.Str, Decl(discriminantPropertyCheck.ts, 70, 12))
inst.value.length;
>inst.value.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
>inst.value : Symbol(StrType.value, Decl(discriminantPropertyCheck.ts, 75, 20))
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
>value : Symbol(StrType.value, Decl(discriminantPropertyCheck.ts, 75, 20))
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
break;
}
case Types.Num: {
>Types.Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
>Types : Symbol(Types, Decl(discriminantPropertyCheck.ts, 66, 1))
>Num : Symbol(Types.Num, Decl(discriminantPropertyCheck.ts, 70, 21))
inst.value.toExponential;
>inst.value.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
>inst.value : Symbol(NumType.value, Decl(discriminantPropertyCheck.ts, 81, 20))
>inst : Symbol(inst, Decl(discriminantPropertyCheck.ts, 85, 15))
>value : Symbol(NumType.value, Decl(discriminantPropertyCheck.ts, 81, 20))
>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --))
break;
}
}
}
}

View File

@ -232,3 +232,81 @@ function foo6(x: Item) {
>length : number
}
}
// Repro from #27493
enum Types { Str = 1, Num = 2 }
>Types : Types
>Str : Types.Str
>1 : 1
>Num : Types.Num
>2 : 2
type Instance = StrType | NumType;
>Instance : Instance
interface StrType {
type: Types.Str;
>type : Types.Str
>Types : any
value: string;
>value : string
length: number;
>length : number
}
interface NumType {
type: Types.Num;
>type : Types.Num
>Types : any
value: number;
>value : number
}
function func2(inst: Instance) {
>func2 : (inst: Instance) => void
>inst : Instance
while (true) {
>true : true
switch (inst.type) {
>inst.type : Types
>inst : Instance
>type : Types
case Types.Str: {
>Types.Str : Types.Str
>Types : typeof Types
>Str : Types.Str
inst.value.length;
>inst.value.length : number
>inst.value : string
>inst : StrType
>value : string
>length : number
break;
}
case Types.Num: {
>Types.Num : Types.Num
>Types : typeof Types
>Num : Types.Num
inst.value.toExponential;
>inst.value.toExponential : (fractionDigits?: number | undefined) => string
>inst.value : number
>inst : NumType
>value : number
>toExponential : (fractionDigits?: number | undefined) => string
break;
}
}
}
}

View File

@ -66,4 +66,36 @@ function foo6(x: Item) {
if (x.foo !== undefined && x.qux) {
x.foo.length; // Error, intervening discriminant guard
}
}
}
// Repro from #27493
enum Types { Str = 1, Num = 2 }
type Instance = StrType | NumType;
interface StrType {
type: Types.Str;
value: string;
length: number;
}
interface NumType {
type: Types.Num;
value: number;
}
function func2(inst: Instance) {
while (true) {
switch (inst.type) {
case Types.Str: {
inst.value.length;
break;
}
case Types.Num: {
inst.value.toExponential;
break;
}
}
}
}