From 3c243dbe0c262ed18a19f1afb0caa302717e9b0d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 27 Jan 2017 14:29:00 -0800 Subject: [PATCH] Remove control flow-based undefined addition Just add undefined when displaying the type. Don't actually add it to the type. --- src/compiler/binder.ts | 12 ------ src/compiler/checker.ts | 92 ++++++++++++++++++----------------------- src/compiler/types.ts | 18 +++----- 3 files changed, 46 insertions(+), 76 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d0acfaed61f..04dc4011a15 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -822,15 +822,6 @@ namespace ts { }; } - function createFlowInitializedParameter(antecedent: FlowNode, node: ParameterDeclaration): FlowNode { - setFlowNodeReferenced(antecedent); - return { - flags: FlowFlags.InitializedParameter, - antecedent, - node - }; - } - function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode { setFlowNodeReferenced(antecedent); return { @@ -2328,9 +2319,6 @@ namespace ts { } else { declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); - if (node.initializer) { - currentFlow = createFlowInitializedParameter(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 34d71a0ab6e..a9c98d02341 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2694,7 +2694,11 @@ namespace ts { writePunctuation(writer, SyntaxKind.ColonToken); writeSpace(writer); - buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, symbolStack); + let type = getTypeOfSymbol(p); + if (strictNullChecks && parameterNode.initializer && !(getModifierFlags(parameterNode) & ModifierFlags.ParameterPropertyModifier)) { + type = includeFalsyTypes(type, TypeFlags.Undefined); + } + buildTypeDisplay(type, writer, enclosingDeclaration, flags, symbolStack); } function buildBindingPatternDisplay(bindingPattern: BindingPattern, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { @@ -3315,9 +3319,7 @@ namespace ts { // Use type from type annotation if one is present if (declaration.type) { - const isOptional = declaration.questionToken || - (declaration.initializer && declaration.kind === SyntaxKind.Parameter && !(getModifierFlags(declaration) & ModifierFlags.ParameterPropertyModifier)); - return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ isOptional && includeOptionality); + return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality); } if ((compilerOptions.noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) && @@ -3368,10 +3370,7 @@ namespace ts { // Use the type of the initializer expression if one is present if (declaration.initializer) { const type = checkDeclarationInitializer(declaration); - // initialized parameters (but not parameter properties) are optional - const isOptional = declaration.questionToken || - (declaration.kind === SyntaxKind.Parameter && !(getModifierFlags(declaration) & ModifierFlags.ParameterPropertyModifier)); - return addOptionality(type, isOptional && includeOptionality); + return addOptionality(type, /*optional*/ declaration.questionToken && includeOptionality); } // If it is a short-hand property assignment, use the type of the identifier @@ -7101,8 +7100,8 @@ namespace ts { const sourceParams = source.parameters; const targetParams = target.parameters; for (let i = 0; i < checkCount; i++) { - const s = i < sourceMax ? getTypeOfSymbol(sourceParams[i]) : getRestTypeOfSignature(source); - const t = i < targetMax ? getTypeOfSymbol(targetParams[i]) : getRestTypeOfSignature(target); + const s = i < sourceMax ? getTypeOfParameter(sourceParams[i]) : getRestTypeOfSignature(source); + const t = i < targetMax ? getTypeOfParameter(targetParams[i]) : getRestTypeOfSignature(target); const related = compareTypes(s, t, /*reportErrors*/ false) || compareTypes(t, s, reportErrors); if (!related) { if (reportErrors) { @@ -8299,8 +8298,8 @@ namespace ts { const targetLen = target.parameters.length; for (let i = 0; i < targetLen; i++) { - const s = isRestParameterIndex(source, i) ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]); - const t = isRestParameterIndex(target, i) ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]); + const s = isRestParameterIndex(source, i) ? getRestTypeOfSignature(source) : getTypeOfParameter(source.parameters[i]); + const t = isRestParameterIndex(target, i) ? getRestTypeOfSignature(target) : getTypeOfParameter(target.parameters[i]); const related = compareTypes(s, t); if (!related) { return Ternary.False; @@ -9196,8 +9195,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 || target.kind === SyntaxKind.Parameter) && - getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target); + (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) && + getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source)) === getSymbolOfNode(target); case SyntaxKind.ThisKeyword: return target.kind === SyntaxKind.ThisKeyword; case SyntaxKind.PropertyAccessExpression: @@ -9291,13 +9290,6 @@ namespace ts { return false; } - function getInitializedParameterReducedType(declaredType: UnionType, assignedType: Type) { - if (declaredType === assignedType || getFalsyFlags(assignedType) & TypeFlags.Undefined) { - return declaredType; - } - return getTypeWithFacts(declaredType, TypeFacts.NEUndefined); - } - // Remove those constituent types of declaredType to which no constituent type of assignedType is assignable. // For example, when a variable of type number | string | boolean is assigned a value of type number | boolean, // we remove type string. @@ -9478,7 +9470,7 @@ namespace ts { return links.resolvedType || getTypeOfExpression(node); } - function getInitialTypeOfVariableDeclaration(node: VariableDeclaration | ParameterDeclaration) { + function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) { if (node.initializer) { return getTypeOfInitializer(node.initializer); } @@ -9491,15 +9483,15 @@ namespace ts { return unknownType; } - function getInitialType(node: VariableDeclaration | BindingElement | ParameterDeclaration) { - return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.Parameter ? - getInitialTypeOfVariableDeclaration(node) : + function getInitialType(node: VariableDeclaration | BindingElement) { + return node.kind === SyntaxKind.VariableDeclaration ? + getInitialTypeOfVariableDeclaration(node) : getInitialTypeOfBindingElement(node); } - function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression | ParameterDeclaration) { - return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement || node.kind === SyntaxKind.Parameter ? - getInitialType(node) : + function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression) { + return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ? + getInitialType(node) : getAssignedType(node); } @@ -9768,13 +9760,6 @@ namespace ts { continue; } } - else if (flow.flags & FlowFlags.InitializedParameter) { - type = getTypeAtFlowInitializedParameter(flow as FlowInitializedParameter); - if (!type) { - flow = (flow as FlowInitializedParameter).antecedent; - continue; - } - } else if (flow.flags & FlowFlags.Condition) { type = getTypeAtFlowCondition(flow); } @@ -9822,20 +9807,6 @@ namespace ts { } } - function getTypeAtFlowInitializedParameter(flow: FlowInitializedParameter) { - const node = flow.node; - // Parameter initializers don't really narrow the declared type except to remove undefined. - // If the initializer includes undefined in the type, it doesn't even remove undefined. - if (isMatchingReference(reference, node)) { - if (declaredType.flags & TypeFlags.Union) { - return getInitializedParameterReducedType(declaredType, getInitialOrAssignedType(node)); - } - return declaredType; - } - - return undefined; - } - function getTypeAtFlowAssignment(flow: FlowAssignment) { const node = flow.node; // Assignments only narrow the computed type if the declared type is a union type. Thus, we @@ -14033,10 +14004,21 @@ namespace ts { } } + function getTypeOfParameter(symbol: Symbol) { + const type = getTypeOfSymbol(symbol); + if (strictNullChecks) { + const declaration = symbol.valueDeclaration; + if (declaration && (declaration).initializer) { + return includeFalsyTypes(type, TypeFlags.Undefined); + } + } + return type; + } + function getTypeAtPosition(signature: Signature, pos: number): Type { return signature.hasRestParameter ? - pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) : - pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType; + pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos]) : getRestTypeOfSignature(signature) : + pos < signature.parameters.length ? getTypeOfParameter(signature.parameters[pos]) : anyType; } function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) { @@ -20652,9 +20634,15 @@ namespace ts { function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { // Get type of the symbol if this is the valid symbol otherwise get type at location const symbol = getSymbolOfNode(declaration); - const type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) + let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) ? getWidenedLiteralType(getTypeOfSymbol(symbol)) : unknownType; + if (strictNullChecks && + declaration.kind === SyntaxKind.Parameter && + (declaration as ParameterDeclaration).initializer && + !(getModifierFlags(declaration) & ModifierFlags.ParameterPropertyModifier)) { + type = includeFalsyTypes(type, TypeFlags.Undefined); + } getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 374c7fa89d8..8b49af402cf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2062,13 +2062,12 @@ BranchLabel = 1 << 2, // Non-looping junction LoopLabel = 1 << 3, // Looping junction Assignment = 1 << 4, // Assignment - InitializedParameter = 1 << 5, // Parameter with initializer - TrueCondition = 1 << 6, // Condition known to be true - FalseCondition = 1 << 7, // Condition known to be false - SwitchClause = 1 << 8, // Switch statement clause - ArrayMutation = 1 << 9, // Potential array mutation - Referenced = 1 << 10, // Referenced as antecedent once - Shared = 1 << 11, // Referenced as antecedent more than once + TrueCondition = 1 << 5, // Condition known to be true + FalseCondition = 1 << 6, // Condition known to be false + SwitchClause = 1 << 7, // Switch statement clause + ArrayMutation = 1 << 8, // Potential array mutation + Referenced = 1 << 9, // Referenced as antecedent once + Shared = 1 << 10, // Referenced as antecedent more than once Label = BranchLabel | LoopLabel, Condition = TrueCondition | FalseCondition } @@ -2118,11 +2117,6 @@ antecedent: FlowNode; } - export interface FlowInitializedParameter extends FlowNode { - node: ParameterDeclaration; - antecedent: FlowNode; - } - export type FlowType = Type | IncompleteType; // Incomplete types occur during control flow analysis of loops. An IncompleteType