No iteration type errors during CFA (#37965)

* No iteration type errors during CFA

* Add regression test
This commit is contained in:
Anders Hejlsberg 2020-04-15 10:34:07 -07:00 committed by GitHub
parent 15c3e99cbd
commit 92cd3ae299
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 8 deletions

View File

@ -19793,9 +19793,11 @@ namespace ts {
return getTypeOfSymbol(symbol);
}
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
const expressionType = getTypeOfDottedName(declaration.parent.parent.expression, /*diagnostic*/ undefined);
const statement = declaration.parent.parent;
const expressionType = getTypeOfDottedName(statement.expression, /*diagnostic*/ undefined);
if (expressionType) {
return getForOfIterationType(declaration.parent.parent, expressionType);
const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf;
return checkIteratedTypeOrElementType(use, expressionType, undefinedType, /*errorNode*/ undefined);
}
}
if (diagnostic) {
@ -32025,19 +32027,14 @@ namespace ts {
}
function checkRightHandSideOfForOf(statement: ForOfStatement): Type {
return getForOfIterationType(statement, checkNonNullExpression(statement.expression));
}
function getForOfIterationType(statement: ForOfStatement, expressionType: Type) {
const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf;
return checkIteratedTypeOrElementType(use, expressionType, undefinedType, statement.expression);
return checkIteratedTypeOrElementType(use, checkNonNullExpression(statement.expression), undefinedType, statement.expression);
}
function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type {
if (isTypeAny(inputType)) {
return inputType;
}
return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) || anyType;
}

View File

@ -0,0 +1,25 @@
//// [noIterationTypeErrorsInCFA.ts]
interface F {
d(): void
}
export function doRemove(dds: F | F[]) {
if (!Array.isArray(dds)) {
dds = [dds]
}
for (let n of dds) {
n.d()
}
return dds
}
//// [noIterationTypeErrorsInCFA.js]
export function doRemove(dds) {
if (!Array.isArray(dds)) {
dds = [dds];
}
for (let n of dds) {
n.d();
}
return dds;
}

View File

@ -0,0 +1,36 @@
=== tests/cases/compiler/noIterationTypeErrorsInCFA.ts ===
interface F {
>F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0))
d(): void
>d : Symbol(F.d, Decl(noIterationTypeErrorsInCFA.ts, 0, 13))
}
export function doRemove(dds: F | F[]) {
>doRemove : Symbol(doRemove, Decl(noIterationTypeErrorsInCFA.ts, 2, 1))
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
>F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0))
>F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0))
if (!Array.isArray(dds)) {
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>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)
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
dds = [dds]
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
}
for (let n of dds) {
>n : Symbol(n, Decl(noIterationTypeErrorsInCFA.ts, 7, 12))
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
n.d()
>n.d : Symbol(F.d, Decl(noIterationTypeErrorsInCFA.ts, 0, 13))
>n : Symbol(n, Decl(noIterationTypeErrorsInCFA.ts, 7, 12))
>d : Symbol(F.d, Decl(noIterationTypeErrorsInCFA.ts, 0, 13))
}
return dds
>dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25))
}

View File

@ -0,0 +1,37 @@
=== tests/cases/compiler/noIterationTypeErrorsInCFA.ts ===
interface F {
d(): void
>d : () => void
}
export function doRemove(dds: F | F[]) {
>doRemove : (dds: F | F[]) => F[]
>dds : F | F[]
if (!Array.isArray(dds)) {
>!Array.isArray(dds) : boolean
>Array.isArray(dds) : boolean
>Array.isArray : (arg: any) => arg is any[]
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>dds : F | F[]
dds = [dds]
>dds = [dds] : F[]
>dds : F | F[]
>[dds] : F[]
>dds : F
}
for (let n of dds) {
>n : F
>dds : F[]
n.d()
>n.d() : void
>n.d : () => void
>n : F
>d : () => void
}
return dds
>dds : F[]
}

View File

@ -0,0 +1,15 @@
// @strict: true
// @target: esnext
interface F {
d(): void
}
export function doRemove(dds: F | F[]) {
if (!Array.isArray(dds)) {
dds = [dds]
}
for (let n of dds) {
n.d()
}
return dds
}