From bb6f3ad29a61895fb209f60012f2d8aaaff94d64 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 14 Dec 2016 08:48:39 -0800 Subject: [PATCH] Add parameter initialisers to control flow Also a little code to emit them in declarations, but this doesn't work yet. --- src/compiler/binder.ts | 5 ++++- src/compiler/checker.ts | 20 +++++++++++--------- src/compiler/declarationEmitter.ts | 8 ++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index a6f5993f6c8..4aa55d3dd70 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -810,7 +810,7 @@ namespace ts { }; } - function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode { + function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement | ParameterDeclaration): FlowNode { setFlowNodeReferenced(antecedent); return { flags: FlowFlags.Assignment, @@ -2311,6 +2311,9 @@ namespace ts { } else { declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); + if (node.initializer) { + currentFlow = createFlowAssignment(currentFlow, node); + } } // If this is a property-parameter, then also declare the property symbol into the diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 07fbb2a7164..72438c244f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3245,7 +3245,9 @@ namespace ts { // Use type from type annotation if one is present if (declaration.type) { - return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality); + const isOptional = declaration.questionToken || + (declaration.initializer && declaration.kind === SyntaxKind.Parameter && !(getModifierFlags(declaration) & ModifierFlags.ParameterPropertyModifier)); + return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ isOptional && includeOptionality); } if ((compilerOptions.noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) && @@ -9042,8 +9044,8 @@ namespace ts { switch (source.kind) { case SyntaxKind.Identifier: return target.kind === SyntaxKind.Identifier && getResolvedSymbol(source) === getResolvedSymbol(target) || - (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) && - getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source)) === getSymbolOfNode(target); + (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) && getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source)) === getSymbolOfNode(target) || + target.kind === SyntaxKind.Parameter && getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target); case SyntaxKind.ThisKeyword: return target.kind === SyntaxKind.ThisKeyword; case SyntaxKind.PropertyAccessExpression: @@ -9314,7 +9316,7 @@ namespace ts { return links.resolvedType || getTypeOfExpression(node); } - function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) { + function getInitialTypeOfVariableDeclaration(node: VariableDeclaration | ParameterDeclaration) { if (node.initializer) { return getTypeOfInitializer(node.initializer); } @@ -9327,15 +9329,15 @@ namespace ts { return unknownType; } - function getInitialType(node: VariableDeclaration | BindingElement) { - return node.kind === SyntaxKind.VariableDeclaration ? - getInitialTypeOfVariableDeclaration(node) : + function getInitialType(node: VariableDeclaration | BindingElement | ParameterDeclaration) { + return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.Parameter ? + getInitialTypeOfVariableDeclaration(node) : getInitialTypeOfBindingElement(node); } function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression) { - return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ? - getInitialType(node) : + return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement || node.kind === SyntaxKind.Parameter ? + getInitialType(node) : getAssignedType(node); } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index cd98622e080..23122d05612 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -319,12 +319,12 @@ namespace ts { } } - function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic, addUndefined?: boolean) { writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; write(": "); if (type) { // Write the type - emitType(type); + emitType(type, addUndefined); } else { errorNameNode = declaration.name; @@ -384,7 +384,7 @@ namespace ts { emitType(type); } - function emitType(type: TypeNode | Identifier | QualifiedName) { + function emitType(type: TypeNode | Identifier | QualifiedName, addUndefined?: boolean) { switch (type.kind) { case SyntaxKind.AnyKeyword: case SyntaxKind.StringKeyword: @@ -1593,7 +1593,7 @@ namespace ts { emitTypeOfVariableDeclarationFromTypeLiteral(node); } else if (!hasModifier(node.parent, ModifierFlags.Private)) { - writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError); + writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError, !!node.initializer && !(getModifierFlags(node) & ModifierFlags.ParameterPropertyModifier)); } function getParameterDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {