@@ -531,7 +531,7 @@ namespace ts {
531531
532532 function getNodeLinks(node: Node): NodeLinks {
533533 const nodeId = getNodeId(node);
534- return nodeLinks[nodeId] || (nodeLinks[nodeId] = {});
534+ return nodeLinks[nodeId] || (nodeLinks[nodeId] = { flags: 0 });
535535 }
536536
537537 function isGlobalSourceFile(node: Node) {
@@ -8185,7 +8185,7 @@ namespace ts {
81858185 return incomplete ? { flags: 0, type } : type;
81868186 }
81878187
8188- function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, includeOuterFunctions: boolean ) {
8188+ function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node ) {
81898189 let key: string;
81908190 if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
81918191 return declaredType;
@@ -8237,7 +8237,7 @@ namespace ts {
82378237 else if (flow.flags & FlowFlags.Start) {
82388238 // Check if we should continue with the control flow of the containing function.
82398239 const container = (<FlowStart>flow).container;
8240- if (container && includeOuterFunctions ) {
8240+ if (container && container !== flowContainer && reference.kind !== SyntaxKind.PropertyAccessExpression ) {
82418241 flow = container.flowNode;
82428242 continue;
82438243 }
@@ -8708,21 +8708,52 @@ namespace ts {
87088708 function getControlFlowContainer(node: Node): Node {
87098709 while (true) {
87108710 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) {
87128715 return node;
87138716 }
87148717 }
87158718 }
87168719
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);
87248756 }
8725- return container === declarationContainer;
87268757 }
87278758
87288759 function checkIdentifier(node: Identifier): Type {
@@ -8777,15 +8808,22 @@ namespace ts {
87778808 checkNestedBlockScopedBinding(node, symbol);
87788809
87798810 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) {
87818813 return type;
87828814 }
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);
87898827 if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
87908828 error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol));
87918829 // Return the declared type to reduce follow-on errors
@@ -9038,7 +9076,7 @@ namespace ts {
90389076 if (isClassLike(container.parent)) {
90399077 const symbol = getSymbolOfNode(container.parent);
90409078 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 );
90429080 }
90439081
90449082 if (isInJavaScriptFile(node)) {
@@ -10699,7 +10737,7 @@ namespace ts {
1069910737 !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
1070010738 return propType;
1070110739 }
10702- return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*includeOuterFunctions */ false );
10740+ return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer */ undefined );
1070310741 }
1070410742
1070510743 function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean {
0 commit comments