diff --git a/tsc/internal/checker/flow.go b/tsc/internal/checker/flow.go index 24d2f4f48b566..2d2287aaa803c 100644 --- a/tsc/internal/checker/flow.go +++ b/tsc/internal/checker/flow.go @@ -1060,7 +1060,8 @@ func (c *Checker) getTypeAtSwitchClause(f *FlowState, flow *ast.FlowNode) FlowTy data := flow.Node.AsFlowSwitchClauseData() expr := ast.SkipParentheses(data.SwitchStatement.Expression()) flowType := c.getTypeAtFlowNode(f, flow.Antecedent) - t := flowType.t + nonEvolvingType := c.finalizeEvolvingArrayType(flowType.t) + t := nonEvolvingType switch { case c.isMatchingReference(f.reference, expr): t = c.narrowTypeBySwitchOnDiscriminant(t, data) @@ -1085,6 +1086,9 @@ func (c *Checker) getTypeAtSwitchClause(f *FlowState, flow *ast.FlowNode) FlowTy t = c.narrowTypeBySwitchOnDiscriminantProperty(t, access, data) } } + if t == nonEvolvingType { + return flowType + } return c.newFlowType(t, flowType.incomplete) } diff --git a/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.errors.txt b/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.errors.txt new file mode 100644 index 0000000000000..3b258d60d30c1 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.errors.txt @@ -0,0 +1,90 @@ +narrowSwitchOnEvolvingArrayNoCrash1.ts(2,9): error TS7034: Variable 'a' implicitly has type 'any[]' in some locations where its type cannot be determined. +narrowSwitchOnEvolvingArrayNoCrash1.ts(3,24): error TS7005: Variable 'a' implicitly has an 'any[]' type. +narrowSwitchOnEvolvingArrayNoCrash1.ts(3,34): error TS2678: Type 'number' is not comparable to type 'any[]'. +narrowSwitchOnEvolvingArrayNoCrash1.ts(7,9): error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined. +narrowSwitchOnEvolvingArrayNoCrash1.ts(8,11): error TS7005: Variable 'b' implicitly has an 'any[]' type. +narrowSwitchOnEvolvingArrayNoCrash1.ts(9,10): error TS2678: Type 'number' is not comparable to type 'any[]'. +narrowSwitchOnEvolvingArrayNoCrash1.ts(15,9): error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined. +narrowSwitchOnEvolvingArrayNoCrash1.ts(16,7): error TS7005: Variable 'b' implicitly has an 'any[]' type. +narrowSwitchOnEvolvingArrayNoCrash1.ts(16,7): error TS2367: This comparison appears to be unintentional because the types 'any[]' and 'number' have no overlap. +narrowSwitchOnEvolvingArrayNoCrash1.ts(22,7): error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined. +narrowSwitchOnEvolvingArrayNoCrash1.ts(23,18): error TS7005: Variable 'c' implicitly has an 'any[]' type. +narrowSwitchOnEvolvingArrayNoCrash1.ts(26,13): error TS2322: Type 'string[]' is not assignable to type 'number[]'. + Type 'string' is not assignable to type 'number'. +narrowSwitchOnEvolvingArrayNoCrash1.ts(32,7): error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined. +narrowSwitchOnEvolvingArrayNoCrash1.ts(33,14): error TS7005: Variable 'c' implicitly has an 'any[]' type. +narrowSwitchOnEvolvingArrayNoCrash1.ts(35,11): error TS2322: Type 'string[]' is not assignable to type 'number[]'. + Type 'string' is not assignable to type 'number'. + + +==== narrowSwitchOnEvolvingArrayNoCrash1.ts (15 errors) ==== + function f1() { + const a = []; + ~ +!!! error TS7034: Variable 'a' implicitly has type 'any[]' in some locations where its type cannot be determined. + while (true) switch (a) { case 0: } + ~ +!!! error TS7005: Variable 'a' implicitly has an 'any[]' type. + ~ +!!! error TS2678: Type 'number' is not comparable to type 'any[]'. + } + + function f2() { + const b = []; + ~ +!!! error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined. + switch (b) { + ~ +!!! error TS7005: Variable 'b' implicitly has an 'any[]' type. + case 0: + ~ +!!! error TS2678: Type 'number' is not comparable to type 'any[]'. + b; + } + } + + function f3() { + const b = []; + ~ +!!! error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined. + if (b === 0) { + ~ +!!! error TS7005: Variable 'b' implicitly has an 'any[]' type. + ~~~~~~~ +!!! error TS2367: This comparison appears to be unintentional because the types 'any[]' and 'number' have no overlap. + b; + } + } + + function f4() { + let c = []; + ~ +!!! error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined. + switch (typeof c) { + ~ +!!! error TS7005: Variable 'c' implicitly has an 'any[]' type. + case "object": { + c.push("x"); + const arr: number[] = c; + ~~~ +!!! error TS2322: Type 'string[]' is not assignable to type 'number[]'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + } + } + } + + function f5() { + let c = []; + ~ +!!! error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined. + if (typeof c === "object") { + ~ +!!! error TS7005: Variable 'c' implicitly has an 'any[]' type. + c.push("x"); + const arr: number[] = c; + ~~~ +!!! error TS2322: Type 'string[]' is not assignable to type 'number[]'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + } + } + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.symbols b/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.symbols new file mode 100644 index 0000000000000..17968f7161e06 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.symbols @@ -0,0 +1,84 @@ +//// [tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts] //// + +=== narrowSwitchOnEvolvingArrayNoCrash1.ts === +function f1() { +>f1 : Symbol(f1, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 0, 0)) + + const a = []; +>a : Symbol(a, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 1, 7)) + + while (true) switch (a) { case 0: } +>a : Symbol(a, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 1, 7)) +} + +function f2() { +>f2 : Symbol(f2, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 3, 1)) + + const b = []; +>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 6, 7)) + + switch (b) { +>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 6, 7)) + + case 0: + b; +>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 6, 7)) + } +} + +function f3() { +>f3 : Symbol(f3, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 11, 1)) + + const b = []; +>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 14, 7)) + + if (b === 0) { +>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 14, 7)) + + b; +>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 14, 7)) + } +} + +function f4() { +>f4 : Symbol(f4, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 18, 1)) + + let c = []; +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5)) + + switch (typeof c) { +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5)) + + case "object": { + c.push("x"); +>c.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) + + const arr: number[] = c; +>arr : Symbol(arr, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 25, 11)) +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5)) + } + } +} + +function f5() { +>f5 : Symbol(f5, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 28, 1)) + + let c = []; +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5)) + + if (typeof c === "object") { +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5)) + + c.push("x"); +>c.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) + + const arr: number[] = c; +>arr : Symbol(arr, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 34, 9)) +>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5)) + } +} + diff --git a/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.types b/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.types new file mode 100644 index 0000000000000..1872fba1ce60f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/narrowSwitchOnEvolvingArrayNoCrash1.types @@ -0,0 +1,105 @@ +//// [tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts] //// + +=== narrowSwitchOnEvolvingArrayNoCrash1.ts === +function f1() { +>f1 : () => void + + const a = []; +>a : any[] +>[] : never[] + + while (true) switch (a) { case 0: } +>true : true +>a : any[] +>0 : 0 +} + +function f2() { +>f2 : () => void + + const b = []; +>b : any[] +>[] : never[] + + switch (b) { +>b : any[] + + case 0: +>0 : 0 + + b; +>b : never + } +} + +function f3() { +>f3 : () => void + + const b = []; +>b : any[] +>[] : never[] + + if (b === 0) { +>b === 0 : boolean +>b : any[] +>0 : 0 + + b; +>b : never + } +} + +function f4() { +>f4 : () => void + + let c = []; +>c : any[] +>[] : never[] + + switch (typeof c) { +>typeof c : "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined" +>c : any[] + + case "object": { +>"object" : "object" + + c.push("x"); +>c.push("x") : number +>c.push : (...items: any[]) => number +>c : any[] +>push : (...items: any[]) => number +>"x" : "x" + + const arr: number[] = c; +>arr : number[] +>c : string[] + } + } +} + +function f5() { +>f5 : () => void + + let c = []; +>c : any[] +>[] : never[] + + if (typeof c === "object") { +>typeof c === "object" : boolean +>typeof c : "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined" +>c : any[] +>"object" : "object" + + c.push("x"); +>c.push("x") : number +>c.push : (...items: any[]) => number +>c : any[] +>push : (...items: any[]) => number +>"x" : "x" + + const arr: number[] = c; +>arr : number[] +>c : string[] + } +} + diff --git a/tsc/testdata/tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts b/tsc/testdata/tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts new file mode 100644 index 0000000000000..76cce21050d6e --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts @@ -0,0 +1,41 @@ +// @target: es2015 +// @strict: true +// @noEmit: true + +function f1() { + const a = []; + while (true) switch (a) { case 0: } +} + +function f2() { + const b = []; + switch (b) { + case 0: + b; + } +} + +function f3() { + const b = []; + if (b === 0) { + b; + } +} + +function f4() { + let c = []; + switch (typeof c) { + case "object": { + c.push("x"); + const arr: number[] = c; + } + } +} + +function f5() { + let c = []; + if (typeof c === "object") { + c.push("x"); + const arr: number[] = c; + } +}