Skip to content

Commit 23f25c7

Browse files
committed
Narrow like we're executing
1 parent cf0aa46 commit 23f25c7

9 files changed

+47
-59
lines changed

src/compiler/checker.ts

+20-15
Original file line numberDiff line numberDiff line change
@@ -28040,26 +28040,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2804028040
}
2804128041

2804228042
function narrowTypeBySwitchOnTrue(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type {
28043-
const clauses = switchStatement.caseBlock.clauses.slice(clauseStart, clauseEnd);
28044-
const clausesType = narrowTypeForTrueClauses(type, clauses);
2804528043
const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause);
2804628044
const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd);
28047-
if (hasDefaultClause) {
28048-
// If we have a default in this set of clauses, then the type could also be any of the types
28049-
// that aren't covered by the other cases.
28050-
28051-
const clausesBefore = switchStatement.caseBlock.clauses.slice(0, clauseStart);
28052-
const clausesAfter = switchStatement.caseBlock.clauses.slice(clauseEnd);
2805328045

28054-
const before = narrowTypeForTrueClauses(type, clausesBefore);
28055-
const after = narrowTypeForTrueClauses(type, clausesAfter);
28056-
const other = getUnionType([before, after]);
28057-
28058-
const typeNotOther = filterType(type, t => !isTypeSubsetOf(t, other));
28046+
// First, narrow away all of the cases that preceded this set of cases.
28047+
const clausesBefore = switchStatement.caseBlock.clauses.slice(0, clauseStart);
28048+
for (const clause of clausesBefore) {
28049+
if (clause.kind === SyntaxKind.CaseClause) {
28050+
type = narrowType(type, clause.expression, /*assumeTrue*/ false);
28051+
}
28052+
}
2805928053

28060-
return getUnionType([clausesType, typeNotOther]);
28054+
// If our current set has a default, then none the other cases were hit either.
28055+
if (hasDefaultClause) {
28056+
const clausesAfter = switchStatement.caseBlock.clauses.slice(clauseEnd);
28057+
for (const clause of clausesAfter) {
28058+
if (clause.kind === SyntaxKind.CaseClause) {
28059+
type = narrowType(type, clause.expression, /*assumeTrue*/ false);
28060+
}
28061+
}
28062+
return type;
2806128063
}
28062-
return clausesType;
28064+
28065+
// Now, add back what we learned using the current set of cases.
28066+
const clauses = switchStatement.caseBlock.clauses.slice(clauseStart, clauseEnd);
28067+
return narrowTypeForTrueClauses(type, clauses);
2806328068
}
2806428069

2806528070
function narrowTypeForTrueClauses(type: Type, clauses: CaseOrDefaultClause[]) {

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.errors.txt

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
narrowByClauseExpressionInSwitchTrue3.ts(12,9): error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap.
2+
narrowByClauseExpressionInSwitchTrue3.ts(13,32): error TS2339: Property 'radius' does not exist on type 'never'.
13
narrowByClauseExpressionInSwitchTrue3.ts(15,14): error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap.
24

35

4-
==== narrowByClauseExpressionInSwitchTrue3.ts (1 errors) ====
6+
==== narrowByClauseExpressionInSwitchTrue3.ts (3 errors) ====
57
type Shape =
68
| { kind: "circle", radius: number }
79
| { kind: "square", sideLength: number }
@@ -14,7 +16,11 @@ narrowByClauseExpressionInSwitchTrue3.ts(15,14): error TS2367: This comparison a
1416
}
1517

1618
if (shape.kind === "circle") {
19+
~~~~~~~~~~~~~~~~~~~~~~~
20+
!!! error TS2367: This comparison appears to be unintentional because the types '"square"' and '"circle"' have no overlap.
1721
return Math.PI * shape.radius ** 2;
22+
~~~~~~
23+
!!! error TS2339: Property 'radius' does not exist on type 'never'.
1824
}
1925
else if (shape.kind === "circle") {
2026
~~~~~~~~~~~~~~~~~~~~~~~

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.symbols

+2-4
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,15 @@ function wat(shape: Shape) {
3838
}
3939

4040
if (shape.kind === "circle") {
41-
>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7), Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7))
41+
>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7))
4242
>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13))
43-
>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 7), Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7))
43+
>kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7))
4444

4545
return Math.PI * shape.radius ** 2;
4646
>Math.PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --))
4747
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
4848
>PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --))
49-
>shape.radius : Symbol(radius, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 23))
5049
>shape : Symbol(shape, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 4, 13))
51-
>radius : Symbol(radius, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 1, 23))
5250
}
5351
else if (shape.kind === "circle") {
5452
>shape.kind : Symbol(kind, Decl(narrowByClauseExpressionInSwitchTrue3.ts, 2, 7))

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue3.types

+6-6
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ function wat(shape: Shape) {
4747

4848
if (shape.kind === "circle") {
4949
>shape.kind === "circle" : boolean
50-
>shape.kind : "circle" | "square"
51-
>shape : Shape
52-
>kind : "circle" | "square"
50+
>shape.kind : "square"
51+
>shape : { kind: "square"; sideLength: number; }
52+
>kind : "square"
5353
>"circle" : "circle"
5454

5555
return Math.PI * shape.radius ** 2;
@@ -58,9 +58,9 @@ function wat(shape: Shape) {
5858
>Math : Math
5959
>PI : number
6060
>shape.radius ** 2 : number
61-
>shape.radius : number
62-
>shape : { kind: "circle"; radius: number; }
63-
>radius : number
61+
>shape.radius : any
62+
>shape : never
63+
>radius : any
6464
>2 : 2
6565
}
6666
else if (shape.kind === "circle") {

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue6.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ function isA(x: MyType) {
139139

140140
default:
141141
x.aProps;
142-
>x.aProps : never
142+
>x.aProps : string
143143
>x : A
144-
>aProps : never
144+
>aProps : string
145145

146146
break;
147147
case x.kind === "b":

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue8.types

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function foo(cond1: boolean, cond2: boolean) {
2626
>cond2 : boolean
2727

2828
cond1; // Should be false?
29-
>cond1 : boolean
29+
>cond1 : false
3030

3131
// ^?
3232
cond2; // Should be true
@@ -37,11 +37,11 @@ function foo(cond1: boolean, cond2: boolean) {
3737

3838
default:
3939
cond1; // Should be false?
40-
>cond1 : never
40+
>cond1 : false
4141

4242
// ^?
4343
cond2; // Should be false?
44-
>cond2 : never
44+
>cond2 : false
4545

4646
// ^?
4747
break;

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.errors.txt

-24
This file was deleted.

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.symbols

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class Foo {
3131
default:
3232
let x = this.mine;
3333
>x : Symbol(x, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 13, 19))
34+
>this.mine : Symbol(Foo.mine, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 4, 11))
35+
>this : Symbol(Foo, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 2, 1))
36+
>mine : Symbol(Foo.mine, Decl(narrowByClauseExpressionInSwitchTrue9.ts, 4, 11))
3437
}
3538
}
3639
}

tests/baselines/reference/narrowByClauseExpressionInSwitchTrue9.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ class Foo {
3030
break;
3131
default:
3232
let x = this.mine;
33-
>x : any
34-
>this.mine : any
35-
>this : never
36-
>mine : any
33+
>x : string
34+
>this.mine : string
35+
>this : this
36+
>mine : string
3737
}
3838
}
3939
}

0 commit comments

Comments
 (0)