Skip to content

Commit 92cd3ae

Browse files
authored
No iteration type errors during CFA (microsoft#37965)
* No iteration type errors during CFA * Add regression test
1 parent 15c3e99 commit 92cd3ae

File tree

5 files changed

+118
-8
lines changed

5 files changed

+118
-8
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19793,9 +19793,11 @@ namespace ts {
1979319793
return getTypeOfSymbol(symbol);
1979419794
}
1979519795
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
19796-
const expressionType = getTypeOfDottedName(declaration.parent.parent.expression, /*diagnostic*/ undefined);
19796+
const statement = declaration.parent.parent;
19797+
const expressionType = getTypeOfDottedName(statement.expression, /*diagnostic*/ undefined);
1979719798
if (expressionType) {
19798-
return getForOfIterationType(declaration.parent.parent, expressionType);
19799+
const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf;
19800+
return checkIteratedTypeOrElementType(use, expressionType, undefinedType, /*errorNode*/ undefined);
1979919801
}
1980019802
}
1980119803
if (diagnostic) {
@@ -32025,19 +32027,14 @@ namespace ts {
3202532027
}
3202632028

3202732029
function checkRightHandSideOfForOf(statement: ForOfStatement): Type {
32028-
return getForOfIterationType(statement, checkNonNullExpression(statement.expression));
32029-
}
32030-
32031-
function getForOfIterationType(statement: ForOfStatement, expressionType: Type) {
3203232030
const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf;
32033-
return checkIteratedTypeOrElementType(use, expressionType, undefinedType, statement.expression);
32031+
return checkIteratedTypeOrElementType(use, checkNonNullExpression(statement.expression), undefinedType, statement.expression);
3203432032
}
3203532033

3203632034
function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type {
3203732035
if (isTypeAny(inputType)) {
3203832036
return inputType;
3203932037
}
32040-
3204132038
return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) || anyType;
3204232039
}
3204332040

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [noIterationTypeErrorsInCFA.ts]
2+
interface F {
3+
d(): void
4+
}
5+
export function doRemove(dds: F | F[]) {
6+
if (!Array.isArray(dds)) {
7+
dds = [dds]
8+
}
9+
for (let n of dds) {
10+
n.d()
11+
}
12+
return dds
13+
}
14+
15+
16+
//// [noIterationTypeErrorsInCFA.js]
17+
export function doRemove(dds) {
18+
if (!Array.isArray(dds)) {
19+
dds = [dds];
20+
}
21+
for (let n of dds) {
22+
n.d();
23+
}
24+
return dds;
25+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
=== tests/cases/compiler/noIterationTypeErrorsInCFA.ts ===
2+
interface F {
3+
>F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0))
4+
5+
d(): void
6+
>d : Symbol(F.d, Decl(noIterationTypeErrorsInCFA.ts, 0, 13))
7+
}
8+
export function doRemove(dds: F | F[]) {
9+
>doRemove : Symbol(doRemove, Decl(noIterationTypeErrorsInCFA.ts, 2, 1))
10+
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
11+
>F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0))
12+
>F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0))
13+
14+
if (!Array.isArray(dds)) {
15+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
16+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more)
17+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
18+
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
19+
20+
dds = [dds]
21+
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
22+
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
23+
}
24+
for (let n of dds) {
25+
>n : Symbol(n, Decl(noIterationTypeErrorsInCFA.ts, 7, 12))
26+
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
27+
28+
n.d()
29+
>n.d : Symbol(F.d, Decl(noIterationTypeErrorsInCFA.ts, 0, 13))
30+
>n : Symbol(n, Decl(noIterationTypeErrorsInCFA.ts, 7, 12))
31+
>d : Symbol(F.d, Decl(noIterationTypeErrorsInCFA.ts, 0, 13))
32+
}
33+
return dds
34+
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
35+
}
36+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/compiler/noIterationTypeErrorsInCFA.ts ===
2+
interface F {
3+
d(): void
4+
>d : () => void
5+
}
6+
export function doRemove(dds: F | F[]) {
7+
>doRemove : (dds: F | F[]) => F[]
8+
>dds : F | F[]
9+
10+
if (!Array.isArray(dds)) {
11+
>!Array.isArray(dds) : boolean
12+
>Array.isArray(dds) : boolean
13+
>Array.isArray : (arg: any) => arg is any[]
14+
>Array : ArrayConstructor
15+
>isArray : (arg: any) => arg is any[]
16+
>dds : F | F[]
17+
18+
dds = [dds]
19+
>dds = [dds] : F[]
20+
>dds : F | F[]
21+
>[dds] : F[]
22+
>dds : F
23+
}
24+
for (let n of dds) {
25+
>n : F
26+
>dds : F[]
27+
28+
n.d()
29+
>n.d() : void
30+
>n.d : () => void
31+
>n : F
32+
>d : () => void
33+
}
34+
return dds
35+
>dds : F[]
36+
}
37+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
// @target: esnext
3+
4+
interface F {
5+
d(): void
6+
}
7+
export function doRemove(dds: F | F[]) {
8+
if (!Array.isArray(dds)) {
9+
dds = [dds]
10+
}
11+
for (let n of dds) {
12+
n.d()
13+
}
14+
return dds
15+
}

0 commit comments

Comments
 (0)