Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
35 changes: 34 additions & 1 deletion tests/baselines/reference/discriminantPropertyCheck.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}

55 changes: 54 additions & 1 deletion tests/baselines/reference/discriminantPropertyCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
}
}
83 changes: 83 additions & 0 deletions tests/baselines/reference/discriminantPropertyCheck.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}

78 changes: 78 additions & 0 deletions tests/baselines/reference/discriminantPropertyCheck.types
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}

34 changes: 33 additions & 1 deletion tests/cases/compiler/discriminantPropertyCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}