From 8ed1f24e573585dc999c7465dbe29087dff0fc71 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 23 Nov 2014 08:12:30 -0800 Subject: [PATCH] Fine tuning array and tuple type checks in destructuring --- src/compiler/checker.ts | 55 +++++++++---------- .../diagnosticInformationMap.generated.ts | 3 +- src/compiler/diagnosticMessages.json | 6 +- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 03df66502dd..00968b255a2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -242,7 +242,7 @@ module ts { } else { var message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable - ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; + ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; forEach(source.declarations, node => { error(node.name ? node.name : node, message, symbolToString(source)); }); @@ -1257,8 +1257,8 @@ module ts { ts.forEach(type.symbol.declarations, declaration => declaration.flags & NodeFlags.Static)); var isNonLocalFunctionSymbol = !!(type.symbol.flags & SymbolFlags.Function) && (type.symbol.parent || // is exported function symbol - ts.forEach(type.symbol.declarations, declaration => - declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); + ts.forEach(type.symbol.declarations, declaration => + declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { // typeof is allowed only for static/non local functions @@ -1288,7 +1288,7 @@ module ts { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } - buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature , typeStack); + buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, typeStack); if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.CloseParenToken); } @@ -1467,7 +1467,7 @@ module ts { writeSpace(writer); buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags, typeStack); } - + function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, typeStack?: Type[]) { if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) { // Instantiated signature, write type arguments instead @@ -1653,16 +1653,13 @@ module ts { error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType)); return unknownType; } - if (isTupleType(parentType)) { - var propName = "" + indexOf(pattern.elements, declaration); - var type = getTypeOfPropertyOfType(parentType, propName); - if (!type) { - error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName); - return unknownType; - } - return type; + var propName = "" + indexOf(pattern.elements, declaration); + var type = isTupleType(parentType) ? getTypeOfPropertyOfType(parentType, propName) : getIndexTypeOfType(parentType, IndexKind.Number); + if (!type) { + error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName); + return unknownType; } - return getIndexTypeOfType(parentType, IndexKind.Number); + return type; } function getTypeForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type { @@ -3980,7 +3977,7 @@ module ts { } function isTupleType(type: Type): boolean { - return (type.flags & TypeFlags.Tuple) !== 0; + return !!getPropertyOfType(type, "0"); } function getWidenedTypeOfObjectLiteral(type: Type): Type { @@ -6368,7 +6365,8 @@ module ts { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { // TODO(andersh): Computed property support var name = ((p).name); - var type = getTypeOfPropertyOfType(sourceType, name.text) || + var type = sourceType.flags & TypeFlags.Any ? sourceType : + getTypeOfPropertyOfType(sourceType, name.text) || isNumericName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || getIndexTypeOfType(sourceType, IndexKind.String); if (type) { @@ -6386,27 +6384,26 @@ module ts { } function checkArrayLiteralAssignment(node: ArrayLiteral, sourceType: Type, contextualMapper?: TypeMapper): Type { + // TODOO(andersh): Allow iterable source type in ES6 + if (!isTypeAssignableTo(sourceType, anyArrayType)) { + error(node, Diagnostics.Type_0_is_not_an_array_type, typeToString(sourceType)); + return sourceType; + } var elements = node.elements; for (var i = 0; i < elements.length; i++) { var e = elements[i]; if (e.kind !== SyntaxKind.OmittedExpression) { - if (isTupleType(sourceType)) { - var propName = "" + i; - var type = getTypeOfPropertyOfType(sourceType, propName); - if (!type) { - error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); - } + var propName = "" + i; + var type = sourceType.flags & TypeFlags.Any ? sourceType : + isTupleType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) : + getIndexTypeOfType(sourceType, IndexKind.Number); + if (type) { + checkDestructuringAssignment(e, type, contextualMapper); } else { - var type = getIndexTypeOfType(sourceType, IndexKind.Number); - if (!type) { - error(e, Diagnostics.Type_0_has_no_numeric_index_signature, typeToString(sourceType)); - } + error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); } } - if (type) { - checkDestructuringAssignment(e, type, contextualMapper); - } } return sourceType; } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 2ff4be92fd2..41e34605e2d 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -280,8 +280,7 @@ module ts { An_AMD_module_cannot_have_multiple_name_assignments: { code: 2458, category: DiagnosticCategory.Error, key: "An AMD module cannot have multiple name assignments." }, Type_0_has_no_property_1_and_no_string_index_signature: { code: 2459, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}' and no string index signature." }, Type_0_has_no_property_1: { code: 2460, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}'." }, - Type_0_has_no_numeric_index_signature: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' has no numeric index signature." }, - Type_0_is_not_an_array_type: { code: 2462, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." }, + Type_0_is_not_an_array_type: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." }, Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." }, Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." }, Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e56188eae9f..c3e3f289195 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1116,13 +1116,9 @@ "category": "Error", "code": 2460 }, - "Type '{0}' has no numeric index signature.": { - "category": "Error", - "code": 2461 - }, "Type '{0}' is not an array type.": { "category": "Error", - "code": 2462 + "code": 2461 }, "Import declaration '{0}' is using private name '{1}'.": {