Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error on variables that are used but never initialized #55887

Merged
merged 28 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ecf36a7
error on variables that are used but never uninitialized
Zzzen Sep 27, 2023
8416f98
format
Zzzen Sep 27, 2023
54183fd
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen Sep 27, 2023
ff025b3
fix tests
Zzzen Sep 27, 2023
7bb240f
fix ForInOrOfStatement
Zzzen Sep 28, 2023
8d814cd
reuse `isAssigned` flag
Zzzen Sep 28, 2023
e897198
Merge branch 'main' into check-uninitialized-variables
DanielRosenwasser Apr 5, 2024
5fbd69d
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen Jul 17, 2024
e1262a6
add tests
Zzzen Jul 18, 2024
2942ade
fix compoud assignment
Zzzen Jul 19, 2024
23be105
update error message
Zzzen Jul 19, 2024
8e4e266
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen Jul 20, 2024
d32f696
update baseline
Zzzen Jul 20, 2024
b3edbf0
ignore var declarations
Zzzen Jul 21, 2024
775670c
fix self check
Zzzen Jul 21, 2024
158d0f3
cache isDefinitelyAssigned
Zzzen Jul 23, 2024
6bfa970
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen Jul 23, 2024
66f2210
update error code
Zzzen Jul 23, 2024
44ce876
format
Zzzen Jul 23, 2024
f9a8207
update comments and ignore constant variables
Zzzen Jul 26, 2024
46b735c
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen Jul 27, 2024
1aabd49
reset impl
Zzzen Jul 27, 2024
45c0011
refactor
Zzzen Jul 28, 2024
f0b637f
narrow function scoped variables
Zzzen Jul 28, 2024
bf4bb51
inline variables
Zzzen Aug 4, 2024
10e2cf8
ignore var variables
Zzzen Aug 8, 2024
6c85362
update test
Zzzen Aug 9, 2024
b930faa
update code
Zzzen Aug 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 91 additions & 40 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5748,6 +5748,7 @@ export interface Symbol {
/** @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/** @internal */ constEnumOnlyModule: boolean | undefined; // True if module contains only const enums or other modules with only const enums
/** @internal */ isReferenced?: SymbolFlags; // True if the symbol is referenced elsewhere. Keeps track of the meaning of a reference in case a symbol is both a type parameter and parameter.
/** @internal */ isInitialized?: boolean; // True if the symbol is ever initialized.
gabritto marked this conversation as resolved.
Show resolved Hide resolved
/** @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol?
/** @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments
/** @internal */ assignmentDeclarationMembers?: Map<number, Declaration>; // detected late-bound assignment declarations associated with the symbol
Expand Down
1 change: 1 addition & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8133,6 +8133,7 @@ function Symbol(this: Symbol, flags: SymbolFlags, name: __String) {
this.exportSymbol = undefined;
this.constEnumOnlyModule = undefined;
this.isReferenced = undefined;
this.isInitialized = undefined;
this.isAssigned = undefined;
(this as any).links = undefined; // used by TransientSymbol
}
Expand Down
135 changes: 135 additions & 0 deletions tests/baselines/reference/typeGuardsAsAssertions.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
typeGuardsAsAssertions.ts(3,5): error TS2454: Variable 'cond' is used before being assigned.
typeGuardsAsAssertions.ts(123,9): error TS2454: Variable 'x' is used before being assigned.


==== typeGuardsAsAssertions.ts (2 errors) ====
// Repro from #8513

let cond: boolean;
~~~~
!!! error TS2454: Variable 'cond' is used before being assigned.

export type Optional<a> = Some<a> | None;

export interface None { readonly none: string; }
export interface Some<a> { readonly some: a; }

export const none : None = { none: '' };

export function isSome<a>(value: Optional<a>): value is Some<a> {
return 'some' in value;
}

function someFrom<a>(some: a) {
return { some };
}

export function fn<r>(makeSome: () => r): void {
let result: Optional<r> = none;
result; // None
while (cond) {
result; // Some<r> | None
result = someFrom(isSome(result) ? result.some : makeSome());
result; // Some<r>
}
}

function foo1() {
let x: string | number | boolean = 0;
x; // number
while (cond) {
x; // number, then string | number
x = typeof x === "string" ? x.slice() : "abc";
x; // string
}
x;
}

function foo2() {
let x: string | number | boolean = 0;
x; // number
while (cond) {
x; // number, then string | number
if (typeof x === "string") {
x = x.slice();
}
else {
x = "abc";
}
x; // string
}
x;
}

// Type guards as assertions

function f1() {
let x: string | number | undefined = undefined;
x; // undefined
if (x) {
x; // string | number (guard as assertion)
}
x; // string | number | undefined
}

function f2() {
let x: string | number | undefined = undefined;
x; // undefined
if (typeof x === "string") {
x; // string (guard as assertion)
}
x; // string | undefined
}

function f3() {
let x: string | number | undefined = undefined;
x; // undefined
if (!x) {
return;
}
x; // string | number (guard as assertion)
}

function f4() {
let x: string | number | undefined = undefined;
x; // undefined
if (typeof x === "boolean") {
x; // nothing (boolean not in declared type)
}
x; // undefined
}

function f5(x: string | number) {
if (typeof x === "string" && typeof x === "number") {
x; // number (guard as assertion)
}
else {
x; // string | number
}
x; // string | number
}

function f6() {
let x: string | undefined | null;
x!.slice();
x = "";
x!.slice();
x = undefined;
x!.slice();
x = null;
x!.slice();
x = <undefined | null>undefined;
x!.slice();
x = <string | undefined>"";
x!.slice();
x = <string | null>"";
x!.slice();
}

function f7() {
let x: string;
~
!!! error TS2454: Variable 'x' is used before being assigned.
x!.slice();
}

116 changes: 116 additions & 0 deletions tests/baselines/reference/unusedLocalsInMethod4.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
unusedLocalsInMethod4.ts(2,9): error TS2454: Variable 'x1' is used before being assigned.
unusedLocalsInMethod4.ts(3,9): error TS2454: Variable 'x2' is used before being assigned.
unusedLocalsInMethod4.ts(9,9): error TS2454: Variable 'x8' is used before being assigned.
unusedLocalsInMethod4.ts(10,9): error TS2454: Variable 'x9' is used before being assigned.
unusedLocalsInMethod4.ts(27,9): error TS2454: Variable 'x1' is used before being assigned.
unusedLocalsInMethod4.ts(28,9): error TS2454: Variable 'x2' is used before being assigned.
unusedLocalsInMethod4.ts(34,9): error TS2454: Variable 'x8' is used before being assigned.
unusedLocalsInMethod4.ts(35,9): error TS2454: Variable 'x9' is used before being assigned.
unusedLocalsInMethod4.ts(37,17): error TS2454: Variable 'x1' is used before being assigned.
unusedLocalsInMethod4.ts(38,17): error TS2454: Variable 'x2' is used before being assigned.
unusedLocalsInMethod4.ts(44,17): error TS2454: Variable 'x8' is used before being assigned.
unusedLocalsInMethod4.ts(45,17): error TS2454: Variable 'x9' is used before being assigned.
unusedLocalsInMethod4.ts(49,9): error TS2454: Variable 'x' is used before being assigned.
unusedLocalsInMethod4.ts(57,9): error TS2454: Variable 'x' is used before being assigned.


==== unusedLocalsInMethod4.ts (14 errors) ====
function f<T, NonNull extends {}>() {
let x1: number[]; // should error
~~
!!! error TS2454: Variable 'x1' is used before being assigned.
let x2: number[] | null; // should error
~~
!!! error TS2454: Variable 'x2' is used before being assigned.
let x3: number[] | undefined; // should not error
let x4: number[] | undefined | null; // should not error
let x5!: number[]; // should not error
let x6: any; // should not error
let x7: unknown; // should not error
let x8: T; // should error
~~
!!! error TS2454: Variable 'x8' is used before being assigned.
let x9: NonNull; // should error
~~
!!! error TS2454: Variable 'x9' is used before being assigned.

function foo() {
console.log(x1);
console.log(x2);
console.log(x3);
console.log(x4);
console.log(x5);
console.log(x6);
console.log(x7);
console.log(x8);
console.log(x9);
}
foo();
}

function f2<T, NonNull extends {}>() {
let x1: number[]; // should error
~~
!!! error TS2454: Variable 'x1' is used before being assigned.
let x2: number[] | null; // should error
~~
!!! error TS2454: Variable 'x2' is used before being assigned.
let x3: number[] | undefined; // should not error
let x4: number[] | undefined | null; // should not error
let x5!: number[]; // should not error
let x6: any; // should not error
let x7: unknown; // should not error
let x8: T; // should error
~~
!!! error TS2454: Variable 'x8' is used before being assigned.
let x9: NonNull; // should error
~~
!!! error TS2454: Variable 'x9' is used before being assigned.

console.log(x1);
~~
!!! error TS2454: Variable 'x1' is used before being assigned.
console.log(x2);
~~
!!! error TS2454: Variable 'x2' is used before being assigned.
console.log(x3);
console.log(x4);
console.log(x5);
console.log(x6);
console.log(x7);
console.log(x8);
~~
!!! error TS2454: Variable 'x8' is used before being assigned.
console.log(x9);
~~
!!! error TS2454: Variable 'x9' is used before being assigned.
}

function f3() {
let x: number[];
~
!!! error TS2454: Variable 'x' is used before being assigned.
function foo() {
x.toString();
}
foo();
}

function f4() {
let x: number;
~
!!! error TS2454: Variable 'x' is used before being assigned.
return {
foo() {
return x.toString();
}
};
}

declare let x: number;
function f5() {
x.toString();
}
export default {};


Loading
Loading