@@ -531,7 +531,7 @@ namespace ts {
531
531
532
532
function getNodeLinks(node: Node): NodeLinks {
533
533
const nodeId = getNodeId(node);
534
- return nodeLinks[nodeId] || (nodeLinks[nodeId] = {});
534
+ return nodeLinks[nodeId] || (nodeLinks[nodeId] = { flags: 0 });
535
535
}
536
536
537
537
function isGlobalSourceFile(node: Node) {
@@ -8185,7 +8185,7 @@ namespace ts {
8185
8185
return incomplete ? { flags: 0, type } : type;
8186
8186
}
8187
8187
8188
- function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, includeOuterFunctions: boolean ) {
8188
+ function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node ) {
8189
8189
let key: string;
8190
8190
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
8191
8191
return declaredType;
@@ -8237,7 +8237,7 @@ namespace ts {
8237
8237
else if (flow.flags & FlowFlags.Start) {
8238
8238
// Check if we should continue with the control flow of the containing function.
8239
8239
const container = (<FlowStart>flow).container;
8240
- if (container && includeOuterFunctions ) {
8240
+ if (container && container !== flowContainer && reference.kind !== SyntaxKind.PropertyAccessExpression ) {
8241
8241
flow = container.flowNode;
8242
8242
continue;
8243
8243
}
@@ -8708,21 +8708,52 @@ namespace ts {
8708
8708
function getControlFlowContainer(node: Node): Node {
8709
8709
while (true) {
8710
8710
node = node.parent;
8711
- if (isFunctionLike(node) || node.kind === SyntaxKind.ModuleBlock || node.kind === SyntaxKind.SourceFile || node.kind === SyntaxKind.PropertyDeclaration) {
8711
+ if (isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) ||
8712
+ node.kind === SyntaxKind.ModuleBlock ||
8713
+ node.kind === SyntaxKind.SourceFile ||
8714
+ node.kind === SyntaxKind.PropertyDeclaration) {
8712
8715
return node;
8713
8716
}
8714
8717
}
8715
8718
}
8716
8719
8717
- function isDeclarationIncludedInFlow(reference: Node, declaration: Declaration, includeOuterFunctions: boolean) {
8718
- const declarationContainer = getControlFlowContainer(declaration);
8719
- let container = getControlFlowContainer(reference);
8720
- while (container !== declarationContainer &&
8721
- (container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.ArrowFunction) &&
8722
- (includeOuterFunctions || getImmediatelyInvokedFunctionExpression(<FunctionExpression>container))) {
8723
- container = getControlFlowContainer(container);
8720
+ // Check if a parameter is assigned anywhere within its declaring function.
8721
+ function isParameterAssigned(symbol: Symbol) {
8722
+ const func = <FunctionLikeDeclaration>getRootDeclaration(symbol.valueDeclaration).parent;
8723
+ const links = getNodeLinks(func);
8724
+ if (!(links.flags & NodeCheckFlags.AssignmentsMarked)) {
8725
+ links.flags |= NodeCheckFlags.AssignmentsMarked;
8726
+ if (!hasParentWithAssignmentsMarked(func)) {
8727
+ markParameterAssignments(func);
8728
+ }
8729
+ }
8730
+ return symbol.isAssigned || false;
8731
+ }
8732
+
8733
+ function hasParentWithAssignmentsMarked(node: Node) {
8734
+ while (true) {
8735
+ node = node.parent;
8736
+ if (!node) {
8737
+ return false;
8738
+ }
8739
+ if (isFunctionLike(node) && getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked) {
8740
+ return true;
8741
+ }
8742
+ }
8743
+ }
8744
+
8745
+ function markParameterAssignments(node: Node) {
8746
+ if (node.kind === SyntaxKind.Identifier) {
8747
+ if (isAssignmentTarget(node)) {
8748
+ const symbol = getResolvedSymbol(<Identifier>node);
8749
+ if (symbol.valueDeclaration && getRootDeclaration(symbol.valueDeclaration).kind === SyntaxKind.Parameter) {
8750
+ symbol.isAssigned = true;
8751
+ }
8752
+ }
8753
+ }
8754
+ else {
8755
+ forEachChild(node, markParameterAssignments);
8724
8756
}
8725
- return container === declarationContainer;
8726
8757
}
8727
8758
8728
8759
function checkIdentifier(node: Identifier): Type {
@@ -8777,15 +8808,22 @@ namespace ts {
8777
8808
checkNestedBlockScopedBinding(node, symbol);
8778
8809
8779
8810
const type = getTypeOfSymbol(localOrExportSymbol);
8780
- if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || isAssignmentTarget(node)) {
8811
+ const declaration = localOrExportSymbol.valueDeclaration;
8812
+ if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || isAssignmentTarget(node) || !declaration) {
8781
8813
return type;
8782
8814
}
8783
- const declaration = localOrExportSymbol.valueDeclaration;
8784
- const includeOuterFunctions = isReadonlySymbol(localOrExportSymbol);
8785
- const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || !declaration ||
8786
- getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) ||
8787
- !isDeclarationIncludedInFlow(node, declaration, includeOuterFunctions);
8788
- const flowType = getFlowTypeOfReference(node, type, assumeInitialized, includeOuterFunctions);
8815
+
8816
+ const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter;
8817
+ const declarationContainer = getControlFlowContainer(declaration);
8818
+ let flowContainer = getControlFlowContainer(node);
8819
+ while (flowContainer !== declarationContainer &&
8820
+ (flowContainer.kind === SyntaxKind.FunctionExpression || flowContainer.kind === SyntaxKind.ArrowFunction) &&
8821
+ (isReadonlySymbol(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) {
8822
+ flowContainer = getControlFlowContainer(flowContainer);
8823
+ }
8824
+ const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter ||
8825
+ flowContainer !== declarationContainer || isInAmbientContext(declaration);
8826
+ const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
8789
8827
if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
8790
8828
error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
8791
8829
// Return the declared type to reduce follow-on errors
@@ -9038,7 +9076,7 @@ namespace ts {
9038
9076
if (isClassLike(container.parent)) {
9039
9077
const symbol = getSymbolOfNode(container.parent);
9040
9078
const type = container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
9041
- return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true, /*includeOuterFunctions */ true );
9079
+ return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true, /*flowContainer */ undefined );
9042
9080
}
9043
9081
9044
9082
if (isInJavaScriptFile(node)) {
@@ -10699,7 +10737,7 @@ namespace ts {
10699
10737
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
10700
10738
return propType;
10701
10739
}
10702
- return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*includeOuterFunctions */ false );
10740
+ return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer */ undefined );
10703
10741
}
10704
10742
10705
10743
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
0 commit comments