Merged
Changes from all commits
Show all changes
28 commitsSelect commit Hold shift + click to select a range
ecf36a7
error on variables that are used but never uninitialized
Zzzen8416f98
format
Zzzen54183fd
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzenff025b3
fix tests
Zzzen7bb240f
fix ForInOrOfStatement
Zzzen8d814cd
reuse `isAssigned` flag
Zzzene897198
Merge branch 'main' into check-uninitialized-variables
DanielRosenwasser5fbd69d
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzene1262a6
add tests
Zzzen2942ade
fix compoud assignment
Zzzen23be105
update error message
Zzzen8e4e266
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzend32f696
update baseline
Zzzenb3edbf0
ignore var declarations
Zzzen775670c
fix self check
Zzzen158d0f3
cache isDefinitelyAssigned
Zzzen6bfa970
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen66f2210
update error code
Zzzen44ce876
format
Zzzenf9a8207
update comments and ignore constant variables
Zzzen46b735c
Merge remote-tracking branch 'origin/main' into check-uninitialized-v…
Zzzen1aabd49
reset impl
Zzzen45c0011
refactor
Zzzenf0b637f
narrow function scoped variables
Zzzenbf4bb51
inline variables
Zzzen10e2cf8
ignore var variables
Zzzen6c85362
update test
Zzzenb930faa
update code
ZzzenFile filter
Filter by extension
Conversations
Failed to load comments.
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Failed to load files.
Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -29504,7 +29504,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | ||
node.kind === SyntaxKind.PropertyDeclaration)!; | ||
} | ||
// Check if a parameter or catch variable is assigned anywhere | ||
// Check if a parameter, catch variable, or mutable local variable is assigned anywhere definitely | ||
gabritto marked this conversation as resolved. Show resolved Hide resolvedUh oh!There was an error while loading. Please reload this page. | ||
function isSymbolAssignedDefinitely(symbol: Symbol) { | ||
if (symbol.lastAssignmentPos !== undefined) { | ||
return symbol.lastAssignmentPos < 0; | ||
} | ||
return isSymbolAssigned(symbol) && symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0; | ||
} | ||
// Check if a parameter, catch variable, or mutable local variable is assigned anywhere | ||
function isSymbolAssigned(symbol: Symbol) { | ||
return !isPastLastAssignment(symbol, /*location*/ undefined); | ||
} | ||
@@ -29523,7 +29531,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | ||
markNodeAssignments(parent); | ||
} | ||
} | ||
return !symbol.lastAssignmentPos || location && symbol.lastAssignmentPos < location.pos; | ||
return !symbol.lastAssignmentPos || location && Math.abs(symbol.lastAssignmentPos) < location.pos; | ||
} | ||
// Check if a parameter or catch variable (or their bindings elements) is assigned anywhere | ||
@@ -29557,12 +29565,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | ||
function markNodeAssignments(node: Node) { | ||
switch (node.kind) { | ||
case SyntaxKind.Identifier: | ||
if (isAssignmentTarget(node)) { | ||
const assigmentTarget = getAssignmentTargetKind(node); | ||
if (assigmentTarget !== AssignmentKind.None) { | ||
const symbol = getResolvedSymbol(node as Identifier); | ||
if (isParameterOrMutableLocalVariable(symbol) && symbol.lastAssignmentPos !== Number.MAX_VALUE) { | ||
const referencingFunction = findAncestor(node, isFunctionOrSourceFile); | ||
const declaringFunction = findAncestor(symbol.valueDeclaration, isFunctionOrSourceFile); | ||
symbol.lastAssignmentPos = referencingFunction === declaringFunction ? extendAssignmentPosition(node, symbol.valueDeclaration!) : Number.MAX_VALUE; | ||
const hasDefiniteAssignment = assigmentTarget === AssignmentKind.Definite || (symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0); | ||
if (isParameterOrMutableLocalVariable(symbol)) { | ||
if (symbol.lastAssignmentPos === undefined || Math.abs(symbol.lastAssignmentPos) !== Number.MAX_VALUE) { | ||
const referencingFunction = findAncestor(node, isFunctionOrSourceFile); | ||
const declaringFunction = findAncestor(symbol.valueDeclaration, isFunctionOrSourceFile); | ||
symbol.lastAssignmentPos = referencingFunction === declaringFunction ? extendAssignmentPosition(node, symbol.valueDeclaration!) : Number.MAX_VALUE; | ||
gabritto marked this conversation as resolved. Show resolved Hide resolvedUh oh!There was an error while loading. Please reload this page. | ||
} | ||
if (hasDefiniteAssignment && symbol.lastAssignmentPos > 0) { | ||
symbol.lastAssignmentPos *= -1; | ||
gabritto marked this conversation as resolved. Show resolved Hide resolvedUh oh!There was an error while loading. Please reload this page. | ||
} | ||
} | ||
} | ||
return; | ||
@@ -29572,7 +29587,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | ||
if (!(node as ExportSpecifier).isTypeOnly && !exportDeclaration.isTypeOnly && !exportDeclaration.moduleSpecifier && name.kind !== SyntaxKind.StringLiteral) { | ||
const symbol = resolveEntityName(name, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true); | ||
if (symbol && isParameterOrMutableLocalVariable(symbol)) { | ||
symbol.lastAssignmentPos = Number.MAX_VALUE; | ||
const sign = symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0 ? -1 : 1; | ||
symbol.lastAssignmentPos = sign * Number.MAX_VALUE; | ||
} | ||
} | ||
return; | ||
@@ -30316,6 +30332,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | ||
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); | ||
let declaration = localOrExportSymbol.valueDeclaration; | ||
const immediateDeclaration = declaration; | ||
// If the identifier is declared in a binding pattern for which we're currently computing the implied type and the | ||
// reference occurs with the same binding pattern, return the non-inferrable any type. This for example occurs in | ||
@@ -30405,7 +30422,10 @@ 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 assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) || | ||
const isNeverInitialized = immediateDeclaration && isVariableDeclaration(immediateDeclaration) && !immediateDeclaration.initializer && !immediateDeclaration.exclamationToken && isMutableLocalVariableDeclaration(immediateDeclaration) && !isSymbolAssignedDefinitely(symbol); | ||
const assumeInitialized = isParameter || isAlias || | ||
gabritto marked this conversation as resolved. Show resolved Hide resolvedUh oh!There was an error while loading. Please reload this page. | ||
(isOuterVariable && !isNeverInitialized) || | ||
isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) || | ||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || | ||
isInTypeQuery(node) || isInAmbientOrTypeNode(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || | ||
node.parent.kind === SyntaxKind.NonNullExpression || | ||
@@ -43264,7 +43284,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | ||
case SyntaxKind.MethodDeclaration: | ||
case SyntaxKind.GetAccessor: | ||
case SyntaxKind.SetAccessor: | ||
if (node.body) { // Don't report unused parameters in overloads | ||
// Only report unused parameters on the implementation, not overloads. | ||
if (node.body) { | ||
checkUnusedLocalsAndParameters(node, addDiagnostic); | ||
} | ||
checkUnusedTypeParameters(node, addDiagnostic); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -13,7 +13,7 @@ | ||
// for (<|var { [|property1|]: p1 } of elems|>) { | ||
// } | ||
// var p2; | ||
// for (<|{ [|{| isWriteAccess: true |}property1|] : p2 } of elems|>) { | ||
// for (<|{ [|property1|] : p2 } of elems|>) { | ||
Zzzen marked this conversation as resolved. Show resolved Hide resolvedUh oh!There was an error while loading. Please reload this page. | ||
// } | ||
// === Definitions === | ||
@@ -94,7 +94,7 @@ | ||
// for (<|var { [|property1|]: p1 } of elems|>) { | ||
// } | ||
// var p2; | ||
// for (<|{ [|{| isWriteAccess: true |}property1|] : p2 } of elems|>) { | ||
// for (<|{ [|property1|] : p2 } of elems|>) { | ||
// } | ||
// === Definitions === | ||
@@ -180,7 +180,7 @@ | ||
// for (<|var { /*FIND ALL REFS*/[|property1|]: p1 } of elems|>) { | ||
// } | ||
// var p2; | ||
// for (<|{ [|{| isWriteAccess: true |}property1|] : p2 } of elems|>) { | ||
// for (<|{ [|property1|] : p2 } of elems|>) { | ||
// } | ||
// === Definitions === | ||
@@ -270,7 +270,7 @@ | ||
// for (<|var { [|property1|]: p1 } of elems|>) { | ||
// } | ||
// var p2; | ||
// for (<|{ /*FIND ALL REFS*/[|{| isWriteAccess: true, isDefinition: true |}property1|] : p2 } of elems|>) { | ||
// for (<|{ /*FIND ALL REFS*/[|{| isDefinition: true |}property1|] : p2 } of elems|>) { | ||
// } | ||
// === Definitions === | ||
@@ -358,7 +358,7 @@ | ||
// for (<|var { [|{| defId: 0 |}property1|]: p1 } of elems|>) { | ||
// } | ||
// var p2; | ||
// for (<|{ [|{| defId: 0, isWriteAccess: true |}property1|] : p2 } of elems|>) { | ||
// for (<|{ [|{| defId: 0 |}property1|] : p2 } of elems|>) { | ||
// } | ||
// === Definitions === | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
narrowingPastLastAssignment.ts(88,9): error TS7034: Variable 'x' implicitly has type 'any' in some locations where its type cannot be determined. | ||
narrowingPastLastAssignment.ts(90,20): error TS7005: Variable 'x' implicitly has an 'any' type. | ||
narrowingPastLastAssignment.ts(161,9): error TS18048: 'foo' is possibly 'undefined'. | ||
==== narrowingPastLastAssignment.ts (2 errors) ==== | ||
==== narrowingPastLastAssignment.ts (3 errors) ==== | ||
function action(f: Function) {} | ||
// Narrowings are preserved in closures created past last assignment | ||
@@ -160,4 +161,15 @@ narrowingPastLastAssignment.ts(90,20): error TS7005: Variable 'x' implicitly has | ||
} | ||
values.forEach(v => foo.push(v)); | ||
} | ||
function f13() { | ||
// Test for captured 'var' declaration (as opposed to parameters, let, const). | ||
var foo: string | undefined; | ||
gabritto marked this conversation as resolved. Show resolved Hide resolvedUh oh!There was an error while loading. Please reload this page. | ||
foo = ''; | ||
return () => { | ||
foo.toLocaleLowerCase(); | ||
~~~ | ||
!!! error TS18048: 'foo' is possibly 'undefined'. | ||
} | ||
} |
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.