Fixed an issue causing spurious "used before being assigned" errors in for of/in loops (#61376)

Co-authored-by: Ryan Cavanaugh <RyanCavanaugh@users.noreply.github.com>
This commit is contained in:
Mateusz Burzyński 2026-01-09 01:27:42 +01:00 committed by GitHub
parent 9d364978d3
commit 632479f28d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 489 additions and 1 deletions

View File

@ -31113,7 +31113,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
// declaration container are the same).
const isNeverInitialized = immediateDeclaration && isVariableDeclaration(immediateDeclaration) && !immediateDeclaration.initializer && !immediateDeclaration.exclamationToken && isMutableLocalVariableDeclaration(immediateDeclaration) && !isSymbolAssignedDefinitely(symbol);
const isNeverInitialized = immediateDeclaration && isVariableDeclaration(immediateDeclaration) && !isForInOrOfStatement(immediateDeclaration.parent.parent) && !immediateDeclaration.initializer && !immediateDeclaration.exclamationToken && isMutableLocalVariableDeclaration(immediateDeclaration) && !isSymbolAssignedDefinitely(symbol);
const assumeInitialized = isParameter || isAlias ||
(isOuterVariable && !isNeverInitialized) ||
isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) ||

View File

@ -0,0 +1,84 @@
unusedLocalsInForInOrOf1.ts(2,12): error TS6133: 'f' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(8,7): error TS6133: 'f' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(14,12): error TS6133: 'g' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(20,12): error TS6133: 'f2' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(26,7): error TS6133: 'f2' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(32,12): error TS6133: 'g2' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(38,12): error TS6133: 'f3' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(44,7): error TS6133: 'f3' is declared but its value is never read.
unusedLocalsInForInOrOf1.ts(50,12): error TS6133: 'g3' is declared but its value is never read.
==== unusedLocalsInForInOrOf1.ts (9 errors) ====
for (let x of [1, 2]) {
function f() {
~
!!! error TS6133: 'f' is declared but its value is never read.
x;
}
}
for (let x of [1, 2]) {
let f = () => {
~
!!! error TS6133: 'f' is declared but its value is never read.
x;
};
}
for (const x of [1, 2]) {
function g() {
~
!!! error TS6133: 'g' is declared but its value is never read.
x;
}
}
for (let x in { a: 1, b: 2 }) {
function f2() {
~~
!!! error TS6133: 'f2' is declared but its value is never read.
x;
}
}
for (let x in { a: 1, b: 2 }) {
let f2 = () => {
~~
!!! error TS6133: 'f2' is declared but its value is never read.
x;
};
}
for (const x in { a: 1, b: 2 }) {
function g2() {
~~
!!! error TS6133: 'g2' is declared but its value is never read.
x;
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
function f3() {
~~
!!! error TS6133: 'f3' is declared but its value is never read.
x;
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
let f3 = () => {
~~
!!! error TS6133: 'f3' is declared but its value is never read.
x;
};
}
for (const { x } of [{ x: 1 }, { x: 2 }]) {
function g3() {
~~
!!! error TS6133: 'g3' is declared but its value is never read.
x;
}
}

View File

@ -0,0 +1,117 @@
//// [tests/cases/compiler/unusedLocalsInForInOrOf1.ts] ////
=== unusedLocalsInForInOrOf1.ts ===
for (let x of [1, 2]) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 0, 8))
function f() {
>f : Symbol(f, Decl(unusedLocalsInForInOrOf1.ts, 0, 23))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 0, 8))
}
}
for (let x of [1, 2]) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 6, 8))
let f = () => {
>f : Symbol(f, Decl(unusedLocalsInForInOrOf1.ts, 7, 5))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 6, 8))
};
}
for (const x of [1, 2]) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 12, 10))
function g() {
>g : Symbol(g, Decl(unusedLocalsInForInOrOf1.ts, 12, 25))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 12, 10))
}
}
for (let x in { a: 1, b: 2 }) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 18, 8))
>a : Symbol(a, Decl(unusedLocalsInForInOrOf1.ts, 18, 15))
>b : Symbol(b, Decl(unusedLocalsInForInOrOf1.ts, 18, 21))
function f2() {
>f2 : Symbol(f2, Decl(unusedLocalsInForInOrOf1.ts, 18, 31))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 18, 8))
}
}
for (let x in { a: 1, b: 2 }) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 24, 8))
>a : Symbol(a, Decl(unusedLocalsInForInOrOf1.ts, 24, 15))
>b : Symbol(b, Decl(unusedLocalsInForInOrOf1.ts, 24, 21))
let f2 = () => {
>f2 : Symbol(f2, Decl(unusedLocalsInForInOrOf1.ts, 25, 5))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 24, 8))
};
}
for (const x in { a: 1, b: 2 }) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 30, 10))
>a : Symbol(a, Decl(unusedLocalsInForInOrOf1.ts, 30, 17))
>b : Symbol(b, Decl(unusedLocalsInForInOrOf1.ts, 30, 23))
function g2() {
>g2 : Symbol(g2, Decl(unusedLocalsInForInOrOf1.ts, 30, 33))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 30, 10))
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 36, 10))
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 36, 20))
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 36, 30))
function f3() {
>f3 : Symbol(f3, Decl(unusedLocalsInForInOrOf1.ts, 36, 41))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 36, 10))
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 42, 10))
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 42, 20))
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 42, 30))
let f3 = () => {
>f3 : Symbol(f3, Decl(unusedLocalsInForInOrOf1.ts, 43, 5))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 42, 10))
};
}
for (const { x } of [{ x: 1 }, { x: 2 }]) {
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 48, 12))
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 48, 22))
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 48, 32))
function g3() {
>g3 : Symbol(g3, Decl(unusedLocalsInForInOrOf1.ts, 48, 43))
x;
>x : Symbol(x, Decl(unusedLocalsInForInOrOf1.ts, 48, 12))
}
}

View File

@ -0,0 +1,228 @@
//// [tests/cases/compiler/unusedLocalsInForInOrOf1.ts] ////
=== unusedLocalsInForInOrOf1.ts ===
for (let x of [1, 2]) {
>x : number
> : ^^^^^^
>[1, 2] : number[]
> : ^^^^^^^^
>1 : 1
> : ^
>2 : 2
> : ^
function f() {
>f : () => void
> : ^^^^^^^^^^
x;
>x : number
> : ^^^^^^
}
}
for (let x of [1, 2]) {
>x : number
> : ^^^^^^
>[1, 2] : number[]
> : ^^^^^^^^
>1 : 1
> : ^
>2 : 2
> : ^
let f = () => {
>f : () => void
> : ^^^^^^^^^^
>() => { x; } : () => void
> : ^^^^^^^^^^
x;
>x : number
> : ^^^^^^
};
}
for (const x of [1, 2]) {
>x : number
> : ^^^^^^
>[1, 2] : number[]
> : ^^^^^^^^
>1 : 1
> : ^
>2 : 2
> : ^
function g() {
>g : () => void
> : ^^^^^^^^^^
x;
>x : number
> : ^^^^^^
}
}
for (let x in { a: 1, b: 2 }) {
>x : string
> : ^^^^^^
>{ a: 1, b: 2 } : { a: number; b: number; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>a : number
> : ^^^^^^
>1 : 1
> : ^
>b : number
> : ^^^^^^
>2 : 2
> : ^
function f2() {
>f2 : () => void
> : ^^^^^^^^^^
x;
>x : string
> : ^^^^^^
}
}
for (let x in { a: 1, b: 2 }) {
>x : string
> : ^^^^^^
>{ a: 1, b: 2 } : { a: number; b: number; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>a : number
> : ^^^^^^
>1 : 1
> : ^
>b : number
> : ^^^^^^
>2 : 2
> : ^
let f2 = () => {
>f2 : () => void
> : ^^^^^^^^^^
>() => { x; } : () => void
> : ^^^^^^^^^^
x;
>x : string
> : ^^^^^^
};
}
for (const x in { a: 1, b: 2 }) {
>x : string
> : ^^^^^^
>{ a: 1, b: 2 } : { a: number; b: number; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>a : number
> : ^^^^^^
>1 : 1
> : ^
>b : number
> : ^^^^^^
>2 : 2
> : ^
function g2() {
>g2 : () => void
> : ^^^^^^^^^^
x;
>x : string
> : ^^^^^^
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
>x : number
> : ^^^^^^
>[{ x: 1 }, { x: 2 }] : { x: number; }[]
> : ^^^^^^^^^^^^^^^^
>{ x: 1 } : { x: number; }
> : ^^^^^^^^^^^^^^
>x : number
> : ^^^^^^
>1 : 1
> : ^
>{ x: 2 } : { x: number; }
> : ^^^^^^^^^^^^^^
>x : number
> : ^^^^^^
>2 : 2
> : ^
function f3() {
>f3 : () => void
> : ^^^^^^^^^^
x;
>x : number
> : ^^^^^^
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
>x : number
> : ^^^^^^
>[{ x: 1 }, { x: 2 }] : { x: number; }[]
> : ^^^^^^^^^^^^^^^^
>{ x: 1 } : { x: number; }
> : ^^^^^^^^^^^^^^
>x : number
> : ^^^^^^
>1 : 1
> : ^
>{ x: 2 } : { x: number; }
> : ^^^^^^^^^^^^^^
>x : number
> : ^^^^^^
>2 : 2
> : ^
let f3 = () => {
>f3 : () => void
> : ^^^^^^^^^^
>() => { x; } : () => void
> : ^^^^^^^^^^
x;
>x : number
> : ^^^^^^
};
}
for (const { x } of [{ x: 1 }, { x: 2 }]) {
>x : number
> : ^^^^^^
>[{ x: 1 }, { x: 2 }] : { x: number; }[]
> : ^^^^^^^^^^^^^^^^
>{ x: 1 } : { x: number; }
> : ^^^^^^^^^^^^^^
>x : number
> : ^^^^^^
>1 : 1
> : ^
>{ x: 2 } : { x: number; }
> : ^^^^^^^^^^^^^^
>x : number
> : ^^^^^^
>2 : 2
> : ^
function g3() {
>g3 : () => void
> : ^^^^^^^^^^
x;
>x : number
> : ^^^^^^
}
}

View File

@ -0,0 +1,59 @@
// @strict: true
// @target: esnext
// @noEmit: true
// @noUnusedLocals: true
// @noUnusedParameters: true
for (let x of [1, 2]) {
function f() {
x;
}
}
for (let x of [1, 2]) {
let f = () => {
x;
};
}
for (const x of [1, 2]) {
function g() {
x;
}
}
for (let x in { a: 1, b: 2 }) {
function f2() {
x;
}
}
for (let x in { a: 1, b: 2 }) {
let f2 = () => {
x;
};
}
for (const x in { a: 1, b: 2 }) {
function g2() {
x;
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
function f3() {
x;
}
}
for (let { x } of [{ x: 1 }, { x: 2 }]) {
let f3 = () => {
x;
};
}
for (const { x } of [{ x: 1 }, { x: 2 }]) {
function g3() {
x;
}
}