diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 281985b0ba..dfb5482b09 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -332,10 +332,9 @@ module ts { // symbol as its sole member. To the rest of the system, this symbol will be indistinguishable // from an actual type literal symbol you would have gotten had you used the long form. - var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature; - var symbol = createSymbol(symbolKind, getDeclarationName(node)); - addDeclarationToSymbol(symbol, node, symbolKind); - bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false); + var symbol = createSymbol(SymbolFlags.Signature, getDeclarationName(node)); + addDeclarationToSymbol(symbol, node, SymbolFlags.Signature); + bindChildren(node, SymbolFlags.Signature, /*isBlockScopeContainer:*/ false); var typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type"); addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral); @@ -376,10 +375,13 @@ module ts { } declareSymbol(blockScopeContainer.locals, undefined, node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); } - bindChildren(node, SymbolFlags.BlockScopedVariable, /*isBlockScopeContainer*/ false); } + function getDestructuringParameterName(node: Declaration) { + return "__" + indexOf((node.parent).parameters, node); + } + function bind(node: Node) { node.parent = parent; switch (node.kind) { @@ -387,10 +389,19 @@ module ts { bindDeclaration(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.Parameter: - bindDeclaration(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false); + if (isBindingPattern((node).name)) { + bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node), /*isBlockScopeContainer*/ false); + } + else { + bindDeclaration(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false); + } break; case SyntaxKind.VariableDeclaration: - if (node.flags & NodeFlags.BlockScoped) { + case SyntaxKind.BindingElement: + if (isBindingPattern((node).name)) { + bindChildren(node, 0, /*isBlockScopeContainer*/ false); + } + else if (node.flags & NodeFlags.BlockScoped) { bindBlockScopedVariableDeclaration(node); } else { @@ -399,6 +410,8 @@ module ts { break; case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: + bindDeclaration(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : 0), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); + break; case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: bindDeclaration(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); @@ -407,10 +420,9 @@ module ts { bindDeclaration(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.CallSignature: - bindDeclaration(node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false); - break; case SyntaxKind.ConstructSignature: - bindDeclaration(node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true); + case SyntaxKind.IndexSignature: + bindDeclaration(node, SymbolFlags.Signature, 0, /*isBlockScopeContainer*/ false); break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: @@ -418,12 +430,9 @@ module ts { // as other properties in the object literal. So we use SymbolFlags.PropertyExcludes // so that it will conflict with any other object literal members with the same // name. - bindDeclaration(node, SymbolFlags.Method, + bindDeclaration(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : 0), isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true); break; - case SyntaxKind.IndexSignature: - bindDeclaration(node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false); - break; case SyntaxKind.FunctionDeclaration: bindDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true); break; @@ -483,7 +492,6 @@ module ts { bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((node).filename) + '"', /*isBlockScopeContainer*/ true); break; } - case SyntaxKind.Block: case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: @@ -491,9 +499,8 @@ module ts { case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: case SyntaxKind.SwitchStatement: - bindChildren(node, 0 , true); + bindChildren(node, 0, /*isBlockScopeContainer*/ true); break; - default: var saveParent = parent; parent = node; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4690d0ad75..8c383368df 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -123,8 +123,8 @@ module ts { var numberType = createIntrinsicType(TypeFlags.Number, "number"); var booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean"); var voidType = createIntrinsicType(TypeFlags.Void, "void"); - var undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); - var nullType = createIntrinsicType(TypeFlags.Null, "null"); + var undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.Unwidened, "undefined"); + var nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.Unwidened, "null"); var unknownType = createIntrinsicType(TypeFlags.Any, "unknown"); var resolvingType = createIntrinsicType(TypeFlags.Any, "__resolving__"); @@ -149,6 +149,8 @@ module ts { var globalRegExpType: ObjectType; var globalTemplateStringsArrayType: ObjectType; + var anyArrayType: Type; + var tupleTypes: Map = {}; var unionTypes: Map = {}; var stringLiteralTypes: Map = {}; @@ -239,7 +241,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)); }); @@ -753,17 +755,6 @@ module ts { members, callSignatures, constructSignatures, stringIndexType, numberIndexType); } - function isOptionalProperty(propertySymbol: Symbol): boolean { - // class C { - // constructor(public x?) { } - // } - // - // x is an optional parameter, but it is a required property. - return propertySymbol.valueDeclaration && - hasQuestionToken(propertySymbol.valueDeclaration) && - propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter; - } - function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T { var result: T; for (var location = enclosingDeclaration; location; location = location.parent) { @@ -1291,8 +1282,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 @@ -1333,7 +1324,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); } @@ -1404,7 +1395,7 @@ module ts { var signatures = getSignaturesOfType(t, SignatureKind.Call); for (var j = 0; j < signatures.length; j++) { buildSymbolDisplay(p, writer); - if (isOptionalProperty(p)) { + if (p.flags & SymbolFlags.Optional) { writePunctuation(writer, SyntaxKind.QuestionToken); } buildSignatureDisplay(signatures[j], writer, enclosingDeclaration, globalFlagsToPass, typeStack); @@ -1414,7 +1405,7 @@ module ts { } else { buildSymbolDisplay(p, writer); - if (isOptionalProperty(p)) { + if (p.flags & SymbolFlags.Optional) { writePunctuation(writer, SyntaxKind.QuestionToken); } writePunctuation(writer, SyntaxKind.ColonToken); @@ -1452,7 +1443,7 @@ module ts { writePunctuation(writer, SyntaxKind.DotDotDotToken); } appendSymbolNameOnly(p, writer); - if (hasQuestionToken(p.valueDeclaration) || (p.valueDeclaration).initializer) { + if (hasQuestionToken(p.valueDeclaration) || (p.valueDeclaration).initializer) { writePunctuation(writer, SyntaxKind.QuestionToken); } writePunctuation(writer, SyntaxKind.ColonToken); @@ -1512,7 +1503,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 @@ -1606,6 +1597,7 @@ module ts { function determineIfDeclarationIsVisible() { switch (node.kind) { case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: @@ -1613,8 +1605,7 @@ module ts { case SyntaxKind.FunctionDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.ImportDeclaration: - // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent - var parent = node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent; + var parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) if (!(node.flags & NodeFlags.Export) && !(node.kind !== SyntaxKind.ImportDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { @@ -1670,6 +1661,18 @@ module ts { } } + function getRootDeclaration(node: Node): Node { + while (node.kind === SyntaxKind.BindingElement) { + node = node.parent.parent; + } + return node; + } + + function getDeclarationContainer(node: Node): Node { + node = getRootDeclaration(node); + return node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent; + } + function getTypeOfPrototypeProperty(prototype: Symbol): Type { // TypeScript 1.0 spec (April 2014): 8.4 // Every class automatically contains a static property member named 'prototype', @@ -1679,11 +1682,67 @@ module ts { return classType.typeParameters ? createTypeReference(classType, map(classType.typeParameters, _ => anyType)) : classType; } - function getTypeOfVariableOrParameterOrPropertyDeclaration(declaration: VariableOrParameterOrPropertyDeclaration): Type { + // Return the type of the given property in the given type, or undefined if no such property exists + function getTypeOfPropertyOfType(type: Type, name: string): Type { + var prop = getPropertyOfType(type, name); + return prop ? getTypeOfSymbol(prop) : undefined; + } + + // Return the inferred type for a binding element + function getTypeForBindingElement(declaration: BindingElement): Type { + var pattern = declaration.parent; + var parentType = getTypeForVariableLikeDeclaration(pattern.parent); + // If parent has the unknown (error) type, then so does this binding element + if (parentType === unknownType) { + return unknownType; + } + // If no type was specified or inferred for parent, or if the specified or inferred type is any, + // infer from the initializer of the binding element if one is present. Otherwise, go with the + // undefined or any type of the parent. + if (!parentType || parentType === anyType) { + if (declaration.initializer) { + return checkExpressionCached(declaration.initializer); + } + return parentType; + } + if (pattern.kind === SyntaxKind.ObjectBindingPattern) { + // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) + var name = declaration.propertyName || declaration.name; + // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, + // or otherwise the type of the string index signature. + var type = getTypeOfPropertyOfType(parentType, name.text) || + isNumericName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) || + getIndexTypeOfType(parentType, IndexKind.String); + if (!type) { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name)); + return unknownType; + } + return type; + } + // For an array binding element the specified or inferred type of the parent must be assignable to any[] + if (!isTypeAssignableTo(parentType, anyArrayType)) { + error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType)); + return unknownType; + } + // Use specific property type when parent is a tuple or numeric index type when parent is an array + var propName = "" + indexOf(pattern.elements, declaration); + var type = isTupleLikeType(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 type; + } + + // Return the inferred type for a variable, parameter, or property declaration + function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type { // A variable declared in a for..in statement is always of type any if (declaration.parent.kind === SyntaxKind.ForInStatement) { return anyType; } + if (isBindingPattern(declaration.parent)) { + return getTypeForBindingElement(declaration); + } // Use type from type annotation if one is present if (declaration.type) { return getTypeFromTypeNode(declaration.type); @@ -1705,57 +1764,86 @@ module ts { } // Use the type of the initializer expression if one is present if (declaration.initializer) { - var type = checkAndMarkExpression(declaration.initializer); - // Widening of property assignments is handled by checkObjectLiteral, exclude them here - if (declaration.kind !== SyntaxKind.PropertyAssignment) { - var unwidenedType = type; - type = getWidenedType(type); - if (type !== unwidenedType) { - checkImplicitAny(type); - } - } - return type; + return checkExpressionCached(declaration.initializer); } - - // If it is a short-hand property assignment; Use the type of the identifier + // If it is a short-hand property assignment, use the type of the identifier if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) { - var type = checkIdentifier(declaration.name); - return type + return checkIdentifier(declaration.name); } + // No type specified and nothing can be inferred + return undefined; + } + // Return the type implied by a binding pattern element. This is the type of the initializer of the element if + // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding + // pattern. Otherwise, it is the type any. + function getTypeFromBindingElement(element: BindingElement): Type { + if (element.initializer) { + return getWidenedType(checkExpressionCached(element.initializer)); + } + if (isBindingPattern(element.name)) { + return getTypeFromBindingPattern(element.name); + } + return anyType; + } + + // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself + // and without regard to its context (i.e. without regard any type annotation or initializer associated with the + // declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any] + // and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is + // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring + // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of + // the parameter. + function getTypeFromBindingPattern(pattern: BindingPattern): Type { + if (pattern.kind === SyntaxKind.ArrayBindingPattern) { + return createTupleType(map(pattern.elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e))); + } + var members: SymbolTable = {}; + forEach(pattern.elements, e => { + var flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); + var name = e.propertyName || e.name; + var symbol = createSymbol(flags, name.text); + symbol.type = getTypeFromBindingElement(e); + members[symbol.name] = symbol; + }); + return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined); + } + + // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type + // specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it + // is a bit more involved. For example: + // + // var [x, s = ""] = [1, "one"]; + // + // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the + // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the + // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string. + function getWidenedTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, reportErrors?: boolean): Type { + var type = getTypeForVariableLikeDeclaration(declaration); + if (type) { + if (reportErrors) { + reportErrorsFromWidening(declaration, type); + } + // During a normal type check we'll never get to here with a property assignment (the check of the containing + // object literal uses a different path). We exclude widening only so that language services and type verification + // tools see the actual type. + return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type; + } + // If no type was specified and nothing could be inferred, and if the declaration specifies a binding pattern, use + // the type implied by the binding pattern + if (isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); + } // Rest parameters default to type any[], other parameters default to type any - var type = hasDotDotDotToken(declaration) ? createArrayType(anyType) : anyType; - checkImplicitAny(type); - return type; - - function checkImplicitAny(type: Type) { - if (!fullTypeCheck || !compilerOptions.noImplicitAny) { - return; + type = declaration.dotDotDotToken ? anyArrayType : anyType; + // Report implicit any errors unless this is a private property within an ambient declaration + if (reportErrors && compilerOptions.noImplicitAny) { + var root = getRootDeclaration(declaration); + if (!isPrivateWithinAmbient(root) && !(root.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(root.parent))) { + reportImplicitAnyError(declaration, type); } - // We need to have ended up with 'any', 'any[]', 'any[][]', etc. - if (getInnermostTypeOfNestedArrayTypes(type) !== anyType) { - return; - } - // Ignore privates within ambient contexts; they exist purely for documentative purposes to avoid name clashing. - // (e.g. privates within .d.ts files do not expose type information) - if (isPrivateWithinAmbient(declaration) || (declaration.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(declaration.parent))) { - return; - } - switch (declaration.kind) { - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - var diagnostic = Diagnostics.Member_0_implicitly_has_an_1_type; - break; - case SyntaxKind.Parameter: - var diagnostic = hasDotDotDotToken(declaration) - ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type - : Diagnostics.Parameter_0_implicitly_has_an_1_type; - break; - default: - var diagnostic = Diagnostics.Variable_0_implicitly_has_an_1_type; - } - error(declaration, diagnostic, declarationNameToString(declaration.name), typeToString(type)); } + return type; } function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type { @@ -1772,7 +1860,7 @@ module ts { } // Handle variable, parameter or property links.type = resolvingType; - var type = getTypeOfVariableOrParameterOrPropertyDeclaration(declaration); + var type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); if (links.type === resolvingType) { links.type = type; } @@ -1780,7 +1868,7 @@ module ts { else if (links.type === resolvingType) { links.type = anyType; if (compilerOptions.noImplicitAny) { - var diagnostic = (symbol.valueDeclaration).type ? + var diagnostic = (symbol.valueDeclaration).type ? Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation : Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer; error(symbol.valueDeclaration, diagnostic, symbolToString(symbol)); @@ -2746,11 +2834,16 @@ module ts { } } + function getUnwidenedFlagOfTypes(types: Type[]): TypeFlags { + return forEach(types, t => t.flags & TypeFlags.Unwidened) || 0; + } + function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { var id = getTypeListId(typeArguments); var type = target.instantiations[id]; if (!type) { - type = target.instantiations[id] = createObjectType(TypeFlags.Reference, target.symbol); + var flags = TypeFlags.Reference | getUnwidenedFlagOfTypes(typeArguments); + type = target.instantiations[id] = createObjectType(flags, target.symbol); type.target = target; type.typeArguments = typeArguments; } @@ -3010,7 +3103,7 @@ module ts { var id = getTypeListId(sortedTypes); var type = unionTypes[id]; if (!type) { - type = unionTypes[id] = createObjectType(TypeFlags.Union); + type = unionTypes[id] = createObjectType(TypeFlags.Union | getUnwidenedFlagOfTypes(sortedTypes)); type.types = sortedTypes; } return type; @@ -3023,7 +3116,7 @@ module ts { } return links.resolvedType; } - + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type { var links = getNodeLinks(node); if (!links.resolvedType) { @@ -3373,12 +3466,9 @@ module ts { // Ternary.False if they are not related. function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary { var result: Ternary; - if (relation === identityRelation) { - // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases - if (source === target) return Ternary.True; - } - else { - if (source === target) return Ternary.True; + // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases + if (source === target) return Ternary.True; + if (relation !== identityRelation) { if (target.flags & TypeFlags.Any) return Ternary.True; if (source === undefinedType) return Ternary.True; if (source === nullType && target !== undefinedType) return Ternary.True; @@ -3389,14 +3479,37 @@ module ts { if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; } } - if (source.flags & TypeFlags.Union) { - if (result = unionTypeRelatedToType(source, target, reportErrors)) { - return result; + if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) { + if (relation === identityRelation) { + if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToUnionType(source, target)) { + if (result &= unionTypeRelatedToUnionType(target, source)) { + return result; + } + } + } + else if (source.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = unionTypeRelatedToType(target, source, reportErrors)) { + return result; + } + } } - } - else if (target.flags & TypeFlags.Union) { - if (result = typeRelatedToUnionType(source, target, reportErrors)) { - return result; + else { + if (source.flags & TypeFlags.Union) { + if (result = unionTypeRelatedToType(source, target, reportErrors)) { + return result; + } + } + else { + if (result = typeRelatedToUnionType(source, target, reportErrors)) { + return result; + } + } } } else if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) { @@ -3430,6 +3543,19 @@ module ts { return Ternary.False; } + function unionTypeRelatedToUnionType(source: UnionType, target: UnionType): Ternary { + var result = Ternary.True; + var sourceTypes = source.types; + for (var i = 0, len = sourceTypes.length; i < len; i++) { + var related = typeRelatedToUnionType(sourceTypes[i], target, false); + if (!related) { + return Ternary.False; + } + result &= related; + } + return result; + } + function typeRelatedToUnionType(source: Type, target: UnionType, reportErrors: boolean): Ternary { var targetTypes = target.types; for (var i = 0, len = targetTypes.length; i < len; i++) { @@ -3500,7 +3626,7 @@ module ts { if (overflow) { return Ternary.False; } - var id = source.id + "," + target.id; + var id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id; var related = relation[id]; if (related !== undefined) { return related ? Ternary.True : Ternary.False; @@ -3598,7 +3724,7 @@ module ts { var sourceProp = getPropertyOfType(source, targetProp.name); if (sourceProp !== targetProp) { if (!sourceProp) { - if (relation === subtypeRelation || !isOptionalProperty(targetProp)) { + if (relation === subtypeRelation || !(targetProp.flags & SymbolFlags.Optional)) { if (reportErrors) { reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source)); } @@ -3650,7 +3776,7 @@ module ts { return Ternary.False; } result &= related; - if (isOptionalProperty(sourceProp) && !isOptionalProperty(targetProp)) { + if (sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) { // TypeScript 1.0 spec (April 2014): 3.8.3 // S is a subtype of a type T, and T is a supertype of S if ... // S' and T are object types and, for each member M in T.. @@ -3822,7 +3948,7 @@ module ts { return related; } return Ternary.True; - } + } function numberIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary { if (relation === identityRelation) { @@ -3891,7 +4017,7 @@ module ts { } } else { - if (isOptionalProperty(sourceProp) !== isOptionalProperty(targetProp)) { + if ((sourceProp.flags & SymbolFlags.Optional) !== (targetProp.flags & SymbolFlags.Optional)) { return Ternary.False; } } @@ -3997,76 +4123,113 @@ module ts { return type.flags & TypeFlags.Reference && (type).target === globalArrayType; } - function getInnermostTypeOfNestedArrayTypes(type: Type): Type { - while (isArrayType(type)) { - type = (type).typeArguments[0]; + function isTupleLikeType(type: Type): boolean { + return !!getPropertyOfType(type, "0"); + } + + function getWidenedTypeOfObjectLiteral(type: Type): Type { + var properties = getPropertiesOfObjectType(type); + var members: SymbolTable = {}; + forEach(properties, p => { + var symbol = createSymbol(p.flags | SymbolFlags.Transient, p.name); + symbol.declarations = p.declarations; + symbol.parent = p.parent; + symbol.type = getWidenedType(getTypeOfSymbol(p)); + symbol.target = p; + if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration; + members[symbol.name] = symbol; + }); + var stringIndexType = getIndexTypeOfType(type, IndexKind.String); + var numberIndexType = getIndexTypeOfType(type, IndexKind.Number); + if (stringIndexType) stringIndexType = getWidenedType(stringIndexType); + if (numberIndexType) numberIndexType = getWidenedType(numberIndexType); + return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType); + } + + function getWidenedType(type: Type): Type { + if (type.flags & TypeFlags.Unwidened) { + if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) { + return anyType; + } + if (type.flags & TypeFlags.Union) { + return getUnionType(map((type).types, t => getWidenedType(t))); + } + if (isTypeOfObjectLiteral(type)) { + return getWidenedTypeOfObjectLiteral(type); + } + if (isArrayType(type)) { + return createArrayType(getWidenedType((type).typeArguments[0])); + } } return type; } - /* If we are widening on a literal, then we may need to the 'node' parameter for reporting purposes */ - function getWidenedType(type: Type, suppressNoImplicitAnyErrors?: boolean): Type { - if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) { - return anyType; - } + function reportWideningErrorsInType(type: Type): boolean { if (type.flags & TypeFlags.Union) { - return getWidenedTypeOfUnion(type); - } - if (isTypeOfObjectLiteral(type)) { - return getWidenedTypeOfObjectLiteral(type); + var errorReported = false; + forEach((type).types, t => { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } + }); + return errorReported; } if (isArrayType(type)) { - return getWidenedTypeOfArrayLiteral(type); + return reportWideningErrorsInType((type).typeArguments[0]); } - return type; - - function getWidenedTypeOfUnion(type: Type): Type { - return getUnionType(map((type).types, t => getWidenedType(t, suppressNoImplicitAnyErrors))); - } - - function getWidenedTypeOfObjectLiteral(type: Type): Type { - var properties = getPropertiesOfObjectType(type); - if (properties.length) { - var widenedTypes: Type[] = []; - var propTypeWasWidened: boolean = false; - forEach(properties, p => { - var propType = getTypeOfSymbol(p); - var widenedType = getWidenedType(propType); - if (propType !== widenedType) { - propTypeWasWidened = true; - if (!suppressNoImplicitAnyErrors && compilerOptions.noImplicitAny && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(widenedType)); - } + if (isTypeOfObjectLiteral(type)) { + var errorReported = false; + forEach(getPropertiesOfObjectType(type), p => { + var t = getTypeOfSymbol(p); + if (t.flags & TypeFlags.Unwidened) { + if (!reportWideningErrorsInType(t)) { + error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t))); } - widenedTypes.push(widenedType); - }); - if (propTypeWasWidened) { - var members: SymbolTable = {}; - var index = 0; - forEach(properties, p => { - var symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | p.flags, p.name); - symbol.declarations = p.declarations; - symbol.parent = p.parent; - symbol.type = widenedTypes[index++]; - symbol.target = p; - if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration; - members[symbol.name] = symbol; - }); - var stringIndexType = getIndexTypeOfType(type, IndexKind.String); - var numberIndexType = getIndexTypeOfType(type, IndexKind.Number); - if (stringIndexType) stringIndexType = getWidenedType(stringIndexType); - if (numberIndexType) numberIndexType = getWidenedType(numberIndexType); - type = createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexType, numberIndexType); + errorReported = true; } - } - return type; + }); + return errorReported; } + return false; + } - function getWidenedTypeOfArrayLiteral(type: Type): Type { - var elementType = (type).typeArguments[0]; - var widenedType = getWidenedType(elementType, suppressNoImplicitAnyErrors); - type = elementType !== widenedType ? createArrayType(widenedType) : type; - return type; + function reportImplicitAnyError(declaration: Declaration, type: Type) { + var typeAsString = typeToString(getWidenedType(type)); + switch (declaration.kind) { + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertySignature: + var diagnostic = Diagnostics.Member_0_implicitly_has_an_1_type; + break; + case SyntaxKind.Parameter: + var diagnostic = (declaration).dotDotDotToken ? + Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : + Diagnostics.Parameter_0_implicitly_has_an_1_type; + break; + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + if (!declaration.name) { + error(declaration, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + return; + } + var diagnostic = Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; + break; + default: + var diagnostic = Diagnostics.Variable_0_implicitly_has_an_1_type; + } + error(declaration, diagnostic, declarationNameToString(declaration.name), typeAsString); + } + + function reportErrorsFromWidening(declaration: Declaration, type: Type) { + if (fullTypeCheck && compilerOptions.noImplicitAny && type.flags & TypeFlags.Unwidened) { + // Report implicit any error within type if possible, otherwise report error on declaration + if (!reportWideningErrorsInType(type)) { + reportImplicitAnyError(declaration, type); + } } } @@ -4250,7 +4413,7 @@ module ts { } } - function getInferenceCandidates(context: InferenceContext, index: number): Type[]{ + function getInferenceCandidates(context: InferenceContext, index: number): Type[] { var inferences = context.inferences[index]; return inferences.primary || inferences.secondary || emptyArray; } @@ -4329,6 +4492,10 @@ module ts { return type; } + function hasInitializer(node: VariableLikeDeclaration): boolean { + return !!(node.initializer || isBindingPattern(node.parent) && hasInitializer(node.parent.parent)); + } + // Check if a given variable is assigned within a given syntax node function isVariableAssignedWithin(symbol: Symbol, node: Node): boolean { var links = getNodeLinks(node); @@ -4356,8 +4523,8 @@ module ts { return forEachChild(node, isAssignedIn); } - function isAssignedInVariableDeclaration(node: VariableDeclaration) { - if (getSymbolOfNode(node) === symbol && node.initializer) { + function isAssignedInVariableDeclaration(node: VariableLikeDeclaration) { + if (!isBindingPattern(node.name) && getSymbolOfNode(node) === symbol && hasInitializer(node)) { return true; } return forEachChild(node, isAssignedIn); @@ -4368,7 +4535,10 @@ module ts { case SyntaxKind.BinaryExpression: return isAssignedInBinaryExpression(node); case SyntaxKind.VariableDeclaration: - return isAssignedInVariableDeclaration(node); + case SyntaxKind.BindingElement: + return isAssignedInVariableDeclaration(node); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.PropertyAccessExpression: @@ -4626,7 +4796,6 @@ module ts { checkCollisionWithCapturedSuperVariable(node, node); checkCollisionWithCapturedThisVariable(node, node); - checkCollisionWithIndexVariableInGeneratedCode(node, node); return getNarrowedTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol), node); } @@ -4774,7 +4943,7 @@ module ts { container.kind === SyntaxKind.PropertySignature || container.kind === SyntaxKind.Constructor; } - } + } } if (canUseSuperExpression) { @@ -4832,7 +5001,7 @@ module ts { } // If last parameter is contextually rest parameter get its type - if (indexOfParameter === (func.parameters.length - 1) && + if (indexOfParameter === (func.parameters.length - 1) && funcHasRestParameters && contextualSignature.hasRestParameter && func.parameters.length >= contextualSignature.parameters.length) { return getTypeOfSymbol(contextualSignature.parameters[contextualSignature.parameters.length - 1]); } @@ -4843,17 +5012,24 @@ module ts { } // In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer - // expression is the type of the variable, parameter or property. In a parameter declaration of a contextually - // typed function expression, the contextual type of an initializer expression is the contextual type of the - // parameter. + // expression is the type of the variable, parameter or property. Otherwise, in a parameter declaration of a + // contextually typed function expression, the contextual type of an initializer expression is the contextual type + // of the parameter. Otherwise, in a variable or parameter declaration with a binding pattern name, the contextual + // type of an initializer expression is the type implied by the binding pattern. function getContextualTypeForInitializerExpression(node: Expression): Type { - var declaration = node.parent; + var declaration = node.parent; if (node === declaration.initializer) { if (declaration.type) { return getTypeFromTypeNode(declaration.type); } if (declaration.kind === SyntaxKind.Parameter) { - return getContextuallyTypedParameterType(declaration); + var type = getContextuallyTypedParameterType(declaration); + if (type) { + return type; + } + } + if (isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); } } return undefined; @@ -4948,8 +5124,8 @@ module ts { } // Return true if the given contextual type is a tuple-like type - function contextualTypeIsTupleType(type: Type): boolean { - return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => getPropertyOfObjectType(t, "0")) : getPropertyOfObjectType(type, "0")); + function contextualTypeIsTupleLikeType(type: Type): boolean { + return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => isTupleLikeType(t)) : isTupleLikeType(type)); } // Return true if the given contextual type provides an index signature of the given kind @@ -4999,7 +5175,7 @@ module ts { // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. function getContextualTypeForConditionalOperand(node: Expression): Type { var conditional = node.parent; - return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; + return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; } // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily @@ -5018,6 +5194,7 @@ module ts { case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: + case SyntaxKind.BindingElement: return getContextualTypeForInitializerExpression(node); case SyntaxKind.ArrowFunction: case SyntaxKind.ReturnStatement: @@ -5120,6 +5297,23 @@ module ts { return mapper && mapper !== identityMapper; } + // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property + // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is + // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'. + function isAssignmentTarget(node: Node): boolean { + var parent = node.parent; + if (parent.kind === SyntaxKind.BinaryExpression && (parent).operator === SyntaxKind.EqualsToken && (parent).left === node) { + return true; + } + if (parent.kind === SyntaxKind.PropertyAssignment) { + return isAssignmentTarget(parent.parent); + } + if (parent.kind === SyntaxKind.ArrayLiteralExpression) { + return isAssignmentTarget(parent); + } + return false; + } + function checkArrayLiteral(node: ArrayLiteralExpression, contextualMapper?: TypeMapper): Type { var elements = node.elements; if (!elements.length) { @@ -5127,12 +5321,12 @@ module ts { } var elementTypes = map(elements, e => checkExpression(e, contextualMapper)); var contextualType = getContextualType(node); - if (contextualType && contextualTypeIsTupleType(contextualType)) { + if ((contextualType && contextualTypeIsTupleLikeType(contextualType)) || isAssignmentTarget(node)) { return createTupleType(elementTypes); } return createArrayType(getUnionType(elementTypes)); } - + function isNumericName(name: string) { // The intent of numeric names is that // - they are names with text in a numeric form, and that @@ -5157,29 +5351,30 @@ module ts { // with the strings '"Infinity"', '"-Infinity"', and '"NaN"' respectively. return (+name).toString() === name; } - + function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type { var members = node.symbol.members; var properties: SymbolTable = {}; var contextualType = getContextualType(node); + var typeFlags: TypeFlags; for (var id in members) { if (hasProperty(members, id)) { var member = members[id]; if (member.flags & SymbolFlags.Property || isObjectLiteralMethod(member.declarations[0])) { var memberDecl = member.declarations[0]; - var type: Type; if (memberDecl.kind === SyntaxKind.PropertyAssignment) { - type = checkExpression((memberDecl).initializer, contextualMapper); + var type = checkExpression((memberDecl).initializer, contextualMapper); } else if (memberDecl.kind === SyntaxKind.MethodDeclaration) { - type = checkObjectLiteralMethod(memberDecl, contextualMapper); + var type = checkObjectLiteralMethod(memberDecl, contextualMapper); } else { Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment); - type = memberDecl.name.kind === SyntaxKind.ComputedPropertyName + var type = memberDecl.name.kind === SyntaxKind.ComputedPropertyName ? unknownType - : checkExpression(memberDecl.name, contextualMapper); + : checkExpression(memberDecl.name, contextualMapper); } + typeFlags |= type.flags; var prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name); prop.declarations = member.declarations; prop.parent = member.parent; @@ -5212,7 +5407,9 @@ module ts { } var stringIndexType = getIndexType(IndexKind.String); var numberIndexType = getIndexType(IndexKind.Number); - return createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType); + var result = createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType); + result.flags |= (typeFlags & TypeFlags.Unwidened); + return result; function getIndexType(kind: IndexKind) { if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) { @@ -5489,10 +5686,7 @@ module ts { * @param callIsIncomplete Whether or not a call is unfinished, and we should be "lenient" when we have too few arguments. * @param signature The signature whose arity we are comparing. */ - function checkArity(adjustedArgCount: number, - typeArguments: NodeArray, - callIsIncomplete: boolean, - signature: Signature): boolean { + function checkArity(adjustedArgCount: number, typeArguments: NodeArray, callIsIncomplete: boolean, signature: Signature): boolean { // Too many arguments implies incorrect arity. if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) { return false; @@ -5594,7 +5788,7 @@ module ts { var constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined, - Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + Diagnostics.Type_0_does_not_satisfy_the_constraint_1); } } } @@ -6083,7 +6277,7 @@ module ts { var exprType = checkExpression(node.expression); var targetType = getTypeFromTypeNode(node.type); if (fullTypeCheck && targetType !== unknownType) { - var widenedType = getWidenedType(exprType, /*supressNoImplicitAnyErrors*/ true); + var widenedType = getWidenedType(exprType); if (!(isTypeAssignableTo(targetType, widenedType))) { checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other); } @@ -6114,48 +6308,26 @@ module ts { function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type { var contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); if (func.body.kind !== SyntaxKind.Block) { - var unwidenedType = checkAndMarkExpression(func.body, contextualMapper); - var widenedType = getWidenedType(unwidenedType); - - if (fullTypeCheck && compilerOptions.noImplicitAny && !contextualSignature && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { - error(func, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeToString(widenedType)); - } - - return widenedType; + var type = checkExpressionCached(func.body, contextualMapper); } - - // Aggregate the types of expressions within all the return statements. - var types = checkAndAggregateReturnExpressionTypes(func.body, contextualMapper); - - // Try to return the best common type if we have any return expressions. - if (types.length > 0) { + else { + // Aggregate the types of expressions within all the return statements. + var types = checkAndAggregateReturnExpressionTypes(func.body, contextualMapper); + if (types.length === 0) { + return voidType; + } // When return statements are contextually typed we allow the return type to be a union type. Otherwise we require the // return expressions to have a best common supertype. - var commonType = contextualSignature ? getUnionType(types) : getCommonSupertype(types); - if (!commonType) { + var type = contextualSignature ? getUnionType(types) : getCommonSupertype(types); + if (!type) { error(func, Diagnostics.No_best_common_type_exists_among_return_expressions); - return unknownType; } - - var widenedType = getWidenedType(commonType); - - // Check and report for noImplicitAny if the best common type implicitly gets widened to an 'any'/arrays-of-'any' type. - if (fullTypeCheck && compilerOptions.noImplicitAny && !contextualSignature && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { - var typeName = typeToString(widenedType); - - if (func.name) { - error(func, Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type, declarationNameToString(func.name), typeName); - } - else { - error(func, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeName); - } - } - - return widenedType; } - - return voidType; + if (!contextualSignature) { + reportErrorsFromWidening(func, type); + } + return getWidenedType(type); } /// Returns a set of types relating to every return expression relating to a function block. @@ -6165,7 +6337,7 @@ module ts { forEachReturnStatement(body, returnStatement => { var expr = returnStatement.expression; if (expr) { - var type = checkAndMarkExpression(expr, contextualMapper); + var type = checkExpressionCached(expr, contextualMapper); if (!contains(aggregatedTypes, type)) { aggregatedTypes.push(type); } @@ -6423,7 +6595,7 @@ module ts { return (type.flags & TypeFlags.Structured) !== 0; } - function isConstEnumObjectType(type: Type) : boolean { + function isConstEnumObjectType(type: Type): boolean { return type.flags & (TypeFlags.ObjectType | TypeFlags.Anonymous) && type.symbol && isConstEnumSymbol(type.symbol); } @@ -6461,8 +6633,79 @@ module ts { return booleanType; } + function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { + var properties = node.properties; + for (var i = 0; i < properties.length; i++) { + var p = properties[i]; + if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { + // TODO(andersh): Computed property support + var name = (p).name; + var type = sourceType.flags & TypeFlags.Any ? sourceType : + getTypeOfPropertyOfType(sourceType, name.text) || + isNumericName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || + getIndexTypeOfType(sourceType, IndexKind.String); + if (type) { + checkDestructuringAssignment((p).initializer || name, type); + } + else { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(sourceType), declarationNameToString(name)); + } + } + else { + error(p, Diagnostics.Property_assignment_expected); + } + } + return sourceType; + } + + function checkArrayLiteralAssignment(node: ArrayLiteralExpression, 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) { + var propName = "" + i; + var type = sourceType.flags & TypeFlags.Any ? sourceType : + isTupleLikeType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) : + getIndexTypeOfType(sourceType, IndexKind.Number); + if (type) { + checkDestructuringAssignment(e, type, contextualMapper); + } + else { + error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); + } + } + } + return sourceType; + } + + function checkDestructuringAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type { + if (target.kind === SyntaxKind.BinaryExpression && (target).operator === SyntaxKind.EqualsToken) { + checkBinaryExpression(target, contextualMapper); + target = (target).left; + } + if (target.kind === SyntaxKind.ObjectLiteralExpression) { + return checkObjectLiteralAssignment(target, sourceType, contextualMapper); + } + if (target.kind === SyntaxKind.ArrayLiteralExpression) { + return checkArrayLiteralAssignment(target, sourceType, contextualMapper); + } + var targetType = checkExpression(target, contextualMapper); + if (checkReferenceExpression(target, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant)) { + checkTypeAssignableTo(sourceType, targetType, target, /*headMessage*/ undefined); + } + return sourceType; + } + function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) { var operator = node.operator; + if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + return checkDestructuringAssignment(node.left, checkExpression(node.right, contextualMapper), contextualMapper); + } var leftType = checkExpression(node.left, contextualMapper); var rightType = checkExpression(node.right, contextualMapper); switch (operator) { @@ -6499,8 +6742,8 @@ module ts { // if a user tries to apply a bitwise operator to 2 boolean operands // try and return them a helpful suggestion if ((leftType.flags & TypeFlags.Boolean) && - (rightType.flags & TypeFlags.Boolean) && - (suggestedOperator = getSuggestedBooleanOperator(node.operator)) !== undefined) { + (rightType.flags & TypeFlags.Boolean) && + (suggestedOperator = getSuggestedBooleanOperator(node.operator)) !== undefined) { error(node, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(node.operator), tokenToString(suggestedOperator)); } else { @@ -6509,7 +6752,7 @@ module ts { var rightOk = checkArithmeticOperandType(node.right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); if (leftOk && rightOk) { checkAssignmentOperator(numberType); - } + } } return numberType; @@ -6574,8 +6817,8 @@ module ts { case SyntaxKind.CommaToken: return rightType; } - - function getSuggestedBooleanOperator(operator: SyntaxKind): SyntaxKind { + + function getSuggestedBooleanOperator(operator: SyntaxKind): SyntaxKind { switch (operator) { case SyntaxKind.BarToken: case SyntaxKind.BarEqualsToken: @@ -6641,10 +6884,12 @@ module ts { return result; } - function checkAndMarkExpression(node: Expression, contextualMapper?: TypeMapper): Type { - var result = checkExpression(node, contextualMapper); - getNodeLinks(node).flags |= NodeCheckFlags.TypeChecked; - return result; + function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = checkExpression(node, contextualMapper); + } + return links.resolvedType; } function checkObjectLiteralMethod(node: MethodDeclaration, contextualMapper?: TypeMapper): Type { @@ -6780,59 +7025,19 @@ module ts { // TODO: Check multiple declarations are identical } - function checkParameter(parameterDeclaration: ParameterDeclaration) { - checkVariableOrParameterDeclaration(parameterDeclaration); - - if (fullTypeCheck) { - checkCollisionWithIndexVariableInGeneratedCode(parameterDeclaration, parameterDeclaration.name); - - if (parameterDeclaration.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected) && - !(parameterDeclaration.parent.kind === SyntaxKind.Constructor && (parameterDeclaration.parent).body)) { - error(parameterDeclaration, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); - } - if (parameterDeclaration.dotDotDotToken) { - if (!isArrayType(getTypeOfSymbol(parameterDeclaration.symbol))) { - error(parameterDeclaration, Diagnostics.A_rest_parameter_must_be_of_an_array_type); - } - } - else { - if (parameterDeclaration.initializer && !(parameterDeclaration.parent).body) { - error(parameterDeclaration, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); - } + function checkParameter(node: ParameterDeclaration) { + checkVariableLikeDeclaration(node); + var func = getContainingFunction(node); + if (node.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) { + func = getContainingFunction(node); + if (!(func.kind === SyntaxKind.Constructor && func.body)) { + error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); } } - - function checkReferencesInInitializer(n: Node): void { - if (n.kind === SyntaxKind.Identifier) { - var referencedSymbol = getNodeLinks(n).resolvedSymbol; - // check FunctionLikeDeclaration.locals (stores parameters\function local variable) - // if it contains entry with a specified name and if this entry matches the resolved symbol - if (referencedSymbol && referencedSymbol !== unknownSymbol && getSymbol(parameterDeclaration.parent.locals, referencedSymbol.name, SymbolFlags.Value) === referencedSymbol) { - if (referencedSymbol.valueDeclaration.kind === SyntaxKind.Parameter) { - if (referencedSymbol.valueDeclaration === parameterDeclaration) { - error(n, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(parameterDeclaration.name)); - return; - } - var enclosingOrReferencedParameter = - forEach((parameterDeclaration.parent).parameters, p => p === parameterDeclaration || p === referencedSymbol.valueDeclaration ? p : undefined); - - if (enclosingOrReferencedParameter === referencedSymbol.valueDeclaration) { - // legal case - parameter initializer references some parameter strictly on left of current parameter declaration - return; - } - // fall through to error reporting - } - - error(n, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(parameterDeclaration.name), declarationNameToString(n)); - } + if (node.dotDotDotToken) { + if (!isArrayType(getTypeOfSymbol(node.symbol))) { + error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } - else { - forEachChild(n, checkReferencesInInitializer); - } - } - - if (parameterDeclaration.initializer) { - checkReferencesInInitializer(parameterDeclaration.initializer); } } @@ -6878,7 +7083,7 @@ module ts { var seenStringIndexer = false; for (var i = 0, len = indexSymbol.declarations.length; i < len; ++i) { var declaration = indexSymbol.declarations[i]; - if (declaration.parameters.length == 1 && declaration.parameters[0].type) { + if (declaration.parameters.length === 1 && declaration.parameters[0].type) { switch (declaration.parameters[0].type.kind) { case SyntaxKind.StringKeyword: if (!seenStringIndexer) { @@ -6903,9 +7108,7 @@ module ts { } function checkPropertyDeclaration(node: PropertyDeclaration) { - if (fullTypeCheck) { - checkVariableOrParameterOrPropertyInFullTypeCheck(node); - } + checkVariableLikeDeclaration(node); } function checkMethodDeclaration(node: MethodDeclaration) { @@ -6968,7 +7171,7 @@ module ts { // Constructors of classes with no extends clause may not contain super calls, whereas // constructors of derived classes must contain at least one super call somewhere in their function body. if (getClassBaseTypeNode(node.parent)) { - + if (containsSuperCall(node.body)) { // The first statement in the body of a constructor must be a super call if both of the following are true: // - The containing class is a derived class. @@ -7408,7 +7611,7 @@ module ts { case SyntaxKind.ImportDeclaration: var result: SymbolFlags = 0; var target = resolveImport(getSymbolOfNode(d)); - forEach(target.declarations, d => { result |= getDeclarationSpaces(d); } ); + forEach(target.declarations, d => { result |= getDeclarationSpaces(d); }); return result; default: return SymbolFlags.ExportValue; @@ -7455,20 +7658,10 @@ module ts { checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } - // If there is no body and no explicit return type, then report an error. - if (fullTypeCheck && compilerOptions.noImplicitAny && !node.body && !node.type) { - // Ignore privates within ambient contexts; they exist purely for documentative purposes to avoid name clashing. - // (e.g. privates within .d.ts files do not expose type information) - if (!isPrivateWithinAmbient(node)) { - var typeName = typeToString(anyType); - - if (node.name) { - error(node, Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type, declarationNameToString(node.name), typeName); - } - else { - error(node, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeName); - } - } + // Report an implicit any error if there is no body, no explicit return type, and node is not a private method + // in an ambient context + if (compilerOptions.noImplicitAny && !node.body && !node.type && !isPrivateWithinAmbient(node)) { + reportImplicitAnyError(node, anyType); } } @@ -7486,93 +7679,14 @@ module ts { } forEach(node.parameters, p => { - if (p.name && p.name.text === argumentsSymbol.name) { + if (p.name && !isBindingPattern(p.name) && (p.name).text === argumentsSymbol.name) { error(p, Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); } }); } - function checkCollisionWithIndexVariableInGeneratedCode(node: Node, name: Identifier) { - if (!(name && name.text === "_i")) { - return; - } - - if (node.kind === SyntaxKind.Parameter) { - // report error if parameter has name '_i' when: - // - function has implementation (not a signature) - // - function has rest parameters - // - context is not ambient (otherwise no codegen impact) - if ((node.parent).body && hasRestParameters(node.parent) && !isInAmbientContext(node)) { - error(node, Diagnostics.Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter); - } - return; - } - - var symbol = getNodeLinks(node).resolvedSymbol; - if (symbol === unknownSymbol) { - return; - } - - // we would like to discover cases like one below: - // - // var _i = "!"; - // function foo(...a) { - // function bar() { - // var x = { get baz() { return _i; } } - // } - // } - // - // at runtime '_i' referenced in getter will be resolved to the generated index variable '_i' used to initialize rest parameters. - // legitimate case: when '_i' is defined inside the function declaration with rest parameters. - // - // function foo(...a) { - // var _i = "!"; - // function bar() { - // var x = { get baz() { return _i; } } - // } - // } - - //// if resolved symbol for node has more than one declaration - this is definitely an error - //// (there is nothing value-like in the language that can be nested in function and consists of multiple declarations) - //if (symbol.declarations.length > 1) { - // error(node, Diagnostics.Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter); - // return; - //} - - // short gist of the check: - // - otherwise - // - walk to the top of the tree starting from the 'node' - // - at every step check if 'current' node contains any declaration of original node - // yes - return - // no - check if current declaration is function with rest parameters - // yes - report error since '_i' from this function will shadow '_i' defined in the outer scope - // no - go up to the next level - var current = node; - while (current) { - var definedOnCurrentLevel = forEach(symbol.declarations, d => d.parent === current ? d : undefined); - if (definedOnCurrentLevel) { - return; - } - switch (current.kind) { - // all kinds that might have rest parameters - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.ArrowFunction: - case SyntaxKind.Constructor: - if (hasRestParameters(current)) { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter); - return; - } - break; - } - current = current.parent; - } - } - function needCollisionCheckForIdentifier(node: Node, identifier: Identifier, name: string): boolean { - if (!identifier || identifier.text !== name) { + if (!(identifier && identifier.text === name)) { return false; } @@ -7591,7 +7705,8 @@ module ts { return false; } - if (node.kind === SyntaxKind.Parameter && !(node.parent).body) { + var root = getRootDeclaration(node); + if (root.kind === SyntaxKind.Parameter && !(root.parent).body) { // just an overload - no codegen impact return false; } @@ -7657,7 +7772,7 @@ module ts { } // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent - var parent = node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent; + var parent = getDeclarationContainer(node); if (parent.kind === SyntaxKind.SourceFile && isExternalModule(parent)) { // If the declaration happens to be in external module, report error that require and exports are reserved keywords error(name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module, @@ -7665,7 +7780,7 @@ module ts { } } - function checkCollisionWithConstDeclarations(node: VariableOrParameterDeclaration) { + function checkCollisionWithConstDeclarations(node: VariableLikeDeclaration) { // Variable declarations are hoisted to the top of their function scope. They can shadow // block scoped declarations, which bind tighter. this will not be flagged as duplicate definition // by the binder as the declaration scope is different. @@ -7687,7 +7802,7 @@ module ts { if (node.initializer && (node.flags & NodeFlags.BlockScoped) === 0) { var symbol = getSymbolOfNode(node); if (symbol.flags & SymbolFlags.FunctionScopedVariable) { - var localDeclarationSymbol = resolveName(node, node.name.text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); + var localDeclarationSymbol = resolveName(node, (node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); if (localDeclarationSymbol && localDeclarationSymbol !== symbol && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.Const) { error(node, Diagnostics.Cannot_redeclare_block_scoped_variable_0, symbolToString(localDeclarationSymbol)); @@ -7697,58 +7812,104 @@ module ts { } } - function checkVariableOrParameterOrPropertyInFullTypeCheck(node: VariableOrParameterOrPropertyDeclaration) { - Debug.assert(fullTypeCheck); - checkSourceElement(node.type); - - if (hasComputedNameButNotSymbol(node)) { - // Just check the initializer, since this property won't contribute to the enclosing type - return node.initializer ? checkAndMarkExpression(node.initializer) : anyType; + function isParameterDeclaration(node: VariableLikeDeclaration) { + while (node.kind === SyntaxKind.BindingElement) { + node = node.parent.parent; } - - var symbol = getSymbolOfNode(node); - var type: Type; - if (symbol.valueDeclaration !== node) { - type = getTypeOfVariableOrParameterOrPropertyDeclaration(node); - } - else { - type = getTypeOfVariableOrParameterOrProperty(symbol); - } - - if (node.initializer && !(getNodeLinks(node.initializer).flags & NodeCheckFlags.TypeChecked)) { - // Use default messages - checkTypeAssignableTo(checkAndMarkExpression(node.initializer), type, node, /*headMessage*/ undefined); - } - - return type; + return node.kind === SyntaxKind.Parameter; } - function checkVariableOrParameterDeclaration(node: VariableOrParameterDeclaration) { - if (fullTypeCheck) { - var type = checkVariableOrParameterOrPropertyInFullTypeCheck(node); - checkExportsOnMergedDeclarations(node); - if (node.initializer) { - checkCollisionWithConstDeclarations(node); - } - - checkCollisionWithCapturedSuperVariable(node, node.name); - checkCollisionWithCapturedThisVariable(node, node.name); - checkCollisionWithRequireExportsInGeneratedCode(node, node.name); - var symbol = getSymbolOfNode(node); - if (node !== symbol.valueDeclaration) { - // TypeScript 1.0 spec (April 2014): 5.1 - // Multiple declarations for the same variable name in the same declaration space are permitted, - // provided that each declaration associates the same type with the variable. - var typeOfValueDeclaration = getTypeOfVariableOrParameterOrProperty(symbol); - if (typeOfValueDeclaration !== unknownType && type !== unknownType && !isTypeIdenticalTo(typeOfValueDeclaration, type)) { - error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(typeOfValueDeclaration), typeToString(type)); + // Check that a parameter initializer contains no references to parameters declared to the right of itself + function checkParameterInitializer(node: VariableLikeDeclaration): void { + if (getRootDeclaration(node).kind === SyntaxKind.Parameter) { + var func = getContainingFunction(node); + visit(node.initializer); + } + function visit(n: Node) { + if (n.kind === SyntaxKind.Identifier) { + var referencedSymbol = getNodeLinks(n).resolvedSymbol; + // check FunctionLikeDeclaration.locals (stores parameters\function local variable) + // if it contains entry with a specified name and if this entry matches the resolved symbol + if (referencedSymbol && referencedSymbol !== unknownSymbol && getSymbol(func.locals, referencedSymbol.name, SymbolFlags.Value) === referencedSymbol) { + if (referencedSymbol.valueDeclaration.kind === SyntaxKind.Parameter) { + if (referencedSymbol.valueDeclaration === node) { + error(n, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(node.name)); + return; + } + if (referencedSymbol.valueDeclaration.pos < node.pos) { + // legal case - parameter initializer references some parameter strictly on left of current parameter declaration + return; + } + // fall through to error reporting + } + error(n, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(node.name), declarationNameToString(n)); } } + else { + forEachChild(n, visit); + } + } + } + + // Check variable, parameter, or property declaration + function checkVariableLikeDeclaration(node: VariableLikeDeclaration) { + checkSourceElement(node.type); + // For a computed property, just check the initializer and exit + if (hasComputedNameButNotSymbol(node)) { + if (node.initializer) { + checkExpressionCached(node.initializer); + } + return; + } + // For a binding pattern, check contained binding elements + if (isBindingPattern(node.name)) { + forEach((node.name).elements, checkSourceElement); + } + // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body + if (node.initializer && getRootDeclaration(node).kind === SyntaxKind.Parameter && !getContainingFunction(node).body) { + error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); + return; + } + // For a binding pattern, validate the initializer and exit + if (isBindingPattern(node.name)) { + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined); + checkParameterInitializer(node); + } + return; + } + var symbol = getSymbolOfNode(node); + var type = getTypeOfVariableOrParameterOrProperty(symbol); + if (node === symbol.valueDeclaration) { + // Node is the primary declaration of the symbol, just validate the initializer + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined); + checkParameterInitializer(node); + } + } + else { + // Node is a secondary declaration, check that type is identical to primary declaration and check that + // initializer is consistent with type associated with the node + var declarationType = getWidenedTypeForVariableLikeDeclaration(node); + if (type !== unknownType && declarationType !== unknownType && !isTypeIdenticalTo(type, declarationType)) { + error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(type), typeToString(declarationType)); + } + if (node.initializer) { + checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, node, /*headMessage*/ undefined); + } + } + if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { + // We know we don't have a binding pattern or computed name here + checkExportsOnMergedDeclarations(node); + checkCollisionWithConstDeclarations(node); + checkCollisionWithCapturedSuperVariable(node, node.name); + checkCollisionWithCapturedThisVariable(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); } } function checkVariableStatement(node: VariableStatement) { - forEach(node.declarations, checkVariableOrParameterDeclaration); + forEach(node.declarations, checkSourceElement); } function checkExpressionStatement(node: ExpressionStatement) { @@ -7772,7 +7933,7 @@ module ts { } function checkForStatement(node: ForStatement) { - if (node.declarations) forEach(node.declarations, checkVariableOrParameterDeclaration); + if (node.declarations) forEach(node.declarations, checkVariableLikeDeclaration); if (node.initializer) checkExpression(node.initializer); if (node.condition) checkExpression(node.condition); if (node.iterator) checkExpression(node.iterator); @@ -7789,7 +7950,7 @@ module ts { if (node.declarations) { if (node.declarations.length >= 1) { var decl = node.declarations[0]; - checkVariableOrParameterDeclaration(decl); + checkVariableLikeDeclaration(decl); if (decl.type) { error(decl, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation); } @@ -7825,34 +7986,28 @@ module ts { // TODO: Check that target label is valid } + function isGetAccessorWithAnnotatatedSetAccessor(node: FunctionLikeDeclaration) { + return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor))); + } + function checkReturnStatement(node: ReturnStatement) { - if (node.expression && !(getNodeLinks(node.expression).flags & NodeCheckFlags.TypeChecked)) { + if (node.expression) { var func = getContainingFunction(node); if (func) { + var returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); + var exprType = checkExpressionCached(node.expression); if (func.kind === SyntaxKind.SetAccessor) { - if (node.expression) { - error(node.expression, Diagnostics.Setters_cannot_return_a_value); - } + error(node.expression, Diagnostics.Setters_cannot_return_a_value); } else { - var returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func)); - // do assignability check only if we short circuited in determining return type - // - function has explicit type annotation - // - function is getter with no type annotation and setter parameter type is used - // - function is a constructor (will be special cased below) - var checkAssignability = - func.type || - (func.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(getDeclarationOfKind(func.symbol, SyntaxKind.SetAccessor))); - if (checkAssignability) { - checkTypeAssignableTo(checkExpression(node.expression), returnType, node.expression, /*headMessage*/ undefined); - } - else if (func.kind == SyntaxKind.Constructor) { - // constructor doesn't have explicit return type annotation and yet its return type is known - declaring type - // handle constructors and issue specialized error message for them. - if (!isTypeAssignableTo(checkExpression(node.expression), returnType)) { + if (func.kind === SyntaxKind.Constructor) { + if (!isTypeAssignableTo(exprType, returnType)) { error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); } } + else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func)) { + checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined); + } } } } @@ -8647,7 +8802,8 @@ module ts { case SyntaxKind.TryStatement: return checkTryStatement(node); case SyntaxKind.VariableDeclaration: - return Debug.fail("Checker encountered variable declaration"); + case SyntaxKind.BindingElement: + return checkVariableLikeDeclaration(node); case SyntaxKind.ClassDeclaration: return checkClassDeclaration(node); case SyntaxKind.InterfaceDeclaration: @@ -8700,6 +8856,9 @@ module ts { case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.BindingElement: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.PropertyAssignment: @@ -8960,7 +9119,7 @@ module ts { case SyntaxKind.PropertySignature: case SyntaxKind.Parameter: case SyntaxKind.VariableDeclaration: - return node === (parent).type; + return node === (parent).type; case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: @@ -9382,10 +9541,10 @@ module ts { return undefined; } - function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableOrParameterDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { + 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 var symbol = getSymbolOfNode(declaration); - var type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.CallSignature | SymbolFlags.ConstructSignature)) + var type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) ? getTypeOfSymbol(symbol) : unknownType; @@ -9397,6 +9556,10 @@ module ts { getSymbolDisplayBuilder().buildTypeDisplay(getReturnTypeOfSignature(signature), writer, enclosingDeclaration, flags); } + function isUnknownIdentifier(location: Node, name: string): boolean { + return !resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined); + } + function createResolver(): EmitResolver { return { getProgram: () => program, @@ -9416,6 +9579,7 @@ module ts { isSymbolAccessible, isEntityNameVisible, getConstantValue, + isUnknownIdentifier, }; } @@ -9450,12 +9614,12 @@ module ts { globalNumberType = getGlobalType("Number"); globalBooleanType = getGlobalType("Boolean"); globalRegExpType = getGlobalType("RegExp"); - // If we're in ES6 mode, load the TemplateStringsArray. // Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios. globalTemplateStringsArrayType = compilerOptions.target >= ScriptTarget.ES6 ? getGlobalType("TemplateStringsArray") : unknownType; + anyArrayType = createArrayType(anyType); } initializeTypeChecker(); diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 7377c42b23..17dbae83bf 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -140,6 +140,10 @@ module ts { Binary_digit_expected: { code: 1177, category: DiagnosticCategory.Error, key: "Binary digit expected." }, Octal_digit_expected: { code: 1178, category: DiagnosticCategory.Error, key: "Octal digit expected." }, Unexpected_token_expected: { code: 1179, category: DiagnosticCategory.Error, key: "Unexpected token. '{' expected." }, + Property_destructuring_pattern_expected: { code: 1180, category: DiagnosticCategory.Error, key: "Property destructuring pattern expected." }, + Array_element_destructuring_pattern_expected: { code: 1181, category: DiagnosticCategory.Error, key: "Array element destructuring pattern expected." }, + A_destructuring_declaration_must_have_an_initializer: { code: 1182, category: DiagnosticCategory.Error, key: "A destructuring declaration must have an initializer." }, + Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, @@ -232,8 +236,6 @@ module ts { Overload_signature_is_not_compatible_with_function_implementation: { code: 2394, category: DiagnosticCategory.Error, key: "Overload signature is not compatible with function implementation." }, Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local: { code: 2395, category: DiagnosticCategory.Error, key: "Individual declarations in merged declaration {0} must be all exported or all local." }, Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: { code: 2396, category: DiagnosticCategory.Error, key: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters." }, - Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter: { code: 2397, category: DiagnosticCategory.Error, key: "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter." }, - Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter: { code: 2398, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter." }, Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: { code: 2399, category: DiagnosticCategory.Error, key: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference." }, Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: { code: 2400, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference." }, Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: { code: 2401, category: DiagnosticCategory.Error, key: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference." }, @@ -289,6 +291,9 @@ module ts { Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." }, Type_alias_name_cannot_be_0: { code: 2457, category: DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" }, 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_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_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." }, Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f0dba54e1a..a06b71d460 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -552,6 +552,22 @@ "category": "Error", "code": 1179 }, + "Property destructuring pattern expected.": { + "category": "Error", + "code": 1180 + }, + "Array element destructuring pattern expected.": { + "category": "Error", + "code": 1181 + }, + "A destructuring declaration must have an initializer.": { + "category": "Error", + "code": 1182 + }, + "Destructuring declarations are not allowed in ambient contexts.": { + "category": "Error", + "code": 1183 + }, "Duplicate identifier '{0}'.": { "category": "Error", @@ -921,14 +937,6 @@ "category": "Error", "code": 2396 }, - "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.": { - "category": "Error", - "code": 2397 - }, - "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.": { - "category": "Error", - "code": 2398 - }, "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": { "category": "Error", "code": 2399 @@ -1153,6 +1161,18 @@ "category": "Error", "code": 2458 }, + "Type '{0}' has no property '{1}' and no string index signature.": { + "category": "Error", + "code": 2459 + }, + "Type '{0}' has no property '{1}'.": { + "category": "Error", + "code": 2460 + }, + "Type '{0}' is not an array type.": { + "category": "Error", + "code": 2461 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f84f19b256..9428f94bb5 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -441,7 +441,7 @@ module ts { handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning)); } - function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableOrParameterDeclaration, type: TypeNode | StringLiteralExpression, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { + function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode | StringLiteralExpression, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) { writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic; write(": "); if (type) { @@ -1003,7 +1003,7 @@ module ts { } } - function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableOrParameterDeclaration) { + function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableLikeDeclaration) { // if this is property of type literal, // or is parameter of method/call/construct/index signature of type literal // emit only if type is specified @@ -1263,7 +1263,12 @@ module ts { if (node.dotDotDotToken) { write("..."); } - writeTextOfNode(currentSourceFile, node.name); + if (isBindingPattern(node.name)) { + write("_" + indexOf((node.parent).parameters, node)); + } + else { + writeTextOfNode(currentSourceFile, node.name); + } if (node.initializer || hasQuestionToken(node)) { write("?"); } @@ -1490,6 +1495,9 @@ module ts { var currentSourceFile: SourceFile; var extendsEmitted = false; + var tempCount = 0; + var tempVariables: Identifier[]; + var tempParameters: Identifier[]; /** write emitted output to disk*/ var writeEmittedFiles = writeJavaScriptFile; @@ -1885,6 +1893,44 @@ module ts { writeFile(compilerHost, diagnostics, jsFilePath, emitOutput, writeByteOrderMark); } + // Create a temporary variable with a unique unused name. The forLoopVariable parameter signals that the + // name should be one that is appropriate for a for loop variable. + function createTempVariable(location: Node, forLoopVariable?: boolean): Identifier { + var name = forLoopVariable ? "_i" : undefined; + while (true) { + if (name && resolver.isUnknownIdentifier(location, name)) { + break; + } + // _a .. _h, _j ... _z, _0, _1, ... + name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0: 1) + CharacterCodes.a) : tempCount - 25); + tempCount++; + } + var result = createNode(SyntaxKind.Identifier); + result.text = name; + return result; + } + + function recordTempDeclaration(name: Identifier) { + if (!tempVariables) { + tempVariables = []; + } + tempVariables.push(name); + } + + function emitTempDeclarations(newLine: boolean) { + if (tempVariables) { + if (newLine) { + writeLine(); + } + else { + write(" "); + } + write("var "); + emitCommaList(tempVariables); + write(";"); + } + } + function emitTokenText(tokenKind: SyntaxKind, startPos: number, emitFn?: () => void) { var tokenString = tokenToString(tokenKind); if (emitFn) { @@ -1903,16 +1949,13 @@ module ts { } } - function emitTrailingCommaIfPresent(nodeList: NodeArray, isMultiline: boolean): void { + function emitTrailingCommaIfPresent(nodeList: NodeArray): void { if (nodeList.hasTrailingComma) { write(","); - if (isMultiline) { - writeLine(); - } } } - function emitCommaList(nodes: NodeArray, includeTrailingComma: boolean, count?: number) { + function emitCommaList(nodes: Node[], count?: number) { if (!(count >= 0)) { count = nodes.length; } @@ -1923,14 +1966,10 @@ module ts { } emit(nodes[i]); } - - if (includeTrailingComma) { - emitTrailingCommaIfPresent(nodes, /*isMultiline*/ false); - } } } - function emitMultiLineList(nodes: NodeArray, includeTrailingComma: boolean) { + function emitMultiLineList(nodes: Node[]) { if (nodes) { for (var i = 0; i < nodes.length; i++) { if (i) { @@ -1939,10 +1978,6 @@ module ts { writeLine(); emit(nodes[i]); } - - if (includeTrailingComma) { - emitTrailingCommaIfPresent(nodes, /*isMultiline*/ true); - } } } @@ -1970,8 +2005,9 @@ module ts { } function emitLiteral(node: LiteralExpression) { - var text = getLiteralText(); - + var text = compilerOptions.target < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind) ? getTemplateLiteralAsStringLiteral(node) : + node.parent ? getSourceTextOfNodeFromSourceFile(currentSourceFile, node) : + node.text; if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { writer.writeLiteral(text); } @@ -1982,14 +2018,6 @@ module ts { else { write(text); } - - function getLiteralText() { - if (compilerOptions.target < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind)) { - return getTemplateLiteralAsStringLiteral(node) - } - - return getSourceTextOfNodeFromSourceFile(currentSourceFile, node); - } } function getTemplateLiteralAsStringLiteral(node: LiteralExpression): string { @@ -2133,6 +2161,7 @@ module ts { switch (parent.kind) { case SyntaxKind.Parameter: case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.PropertyAssignment: @@ -2171,7 +2200,10 @@ module ts { } function emitIdentifier(node: Identifier) { - if (!isNotExpressionIdentifier(node)) { + if (!node.parent) { + write(node.text); + } + else if (!isNotExpressionIdentifier(node)) { emitExpressionIdentifier(node); } else { @@ -2201,18 +2233,34 @@ module ts { } } + function emitObjectBindingPattern(node: BindingPattern) { + write("{ "); + emitCommaList(node.elements); + emitTrailingCommaIfPresent(node.elements); + write(" }"); + } + + function emitArrayBindingPattern(node: BindingPattern) { + write("["); + emitCommaList(node.elements); + emitTrailingCommaIfPresent(node.elements); + write("]"); + } + function emitArrayLiteral(node: ArrayLiteralExpression) { if (node.flags & NodeFlags.MultiLine) { write("["); increaseIndent(); - emitMultiLineList(node.elements, /*includeTrailingComma*/ true); + emitMultiLineList(node.elements); + emitTrailingCommaIfPresent(node.elements); decreaseIndent(); writeLine(); write("]"); } else { write("["); - emitCommaList(node.elements, /*includeTrailingComma*/ true); + emitCommaList(node.elements); + emitTrailingCommaIfPresent(node.elements); write("]"); } } @@ -2224,14 +2272,20 @@ module ts { else if (node.flags & NodeFlags.MultiLine) { write("{"); increaseIndent(); - emitMultiLineList(node.properties, /*includeTrailingComma*/ compilerOptions.target >= ScriptTarget.ES5); + emitMultiLineList(node.properties); + if (compilerOptions.target >= ScriptTarget.ES5) { + emitTrailingCommaIfPresent(node.properties); + } decreaseIndent(); writeLine(); write("}"); } else { write("{ "); - emitCommaList(node.properties, /*includeTrailingComma*/ compilerOptions.target >= ScriptTarget.ES5); + emitCommaList(node.properties); + if (compilerOptions.target >= ScriptTarget.ES5) { + emitTrailingCommaIfPresent(node.properties); + } write(" }"); } } @@ -2242,30 +2296,19 @@ module ts { write("]"); } - function emitDownlevelMethod(node: MethodDeclaration) { - if (!isObjectLiteralMethod(node)) { - return; - } - - emitLeadingComments(node); - emit(node.name); - write(": "); - write("function "); - emitSignatureAndBody(node); - emitTrailingComments(node); - } - function emitMethod(node: MethodDeclaration) { if (!isObjectLiteralMethod(node)) { return; } - emitLeadingComments(node); emit(node.name); + if (compilerOptions.target < ScriptTarget.ES6) { + write(": function "); + } emitSignatureAndBody(node); emitTrailingComments(node); } - + function emitPropertyAssignment(node: PropertyDeclaration) { emitLeadingComments(node); emit(node.name); @@ -2274,18 +2317,9 @@ module ts { emitTrailingComments(node); } - function emitDownlevelShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { - emitLeadingComments(node); - // Emit identifier as an identifier - emit(node.name); - write(": "); - // Even though this is stored as identifier treat it as an expression - // Short-hand, { x }, is equivalent of normal form { x: x } - emitExpressionIdentifier(node.name); - emitTrailingComments(node); - } - function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { + emitLeadingComments(node); + emit(node.name); // If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example: // module m { // export var y; @@ -2294,16 +2328,14 @@ module ts { // export var obj = { y }; // } // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version - var prefix = resolver.getExpressionNamePrefix(node.name); - if (prefix) { - emitDownlevelShorthandPropertyAssignment(node); - } - // If short-hand property has no prefix, emit it as short-hand. - else { - emitLeadingComments(node); - emit(node.name); - emitTrailingComments(node); + if (compilerOptions.target < ScriptTarget.ES6 || resolver.getExpressionNamePrefix(node.name)) { + // Emit identifier as an identifier + write(": "); + // Even though this is stored as identifier treat it as an expression + // Short-hand, { x }, is equivalent of normal form { x: x } + emitExpressionIdentifier(node.name); } + emitTrailingComments(node); } function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { @@ -2356,13 +2388,13 @@ module ts { emitThis(node.expression); if (node.arguments.length) { write(", "); - emitCommaList(node.arguments, /*includeTrailingComma*/ false); + emitCommaList(node.arguments); } write(")"); } else { write("("); - emitCommaList(node.arguments, /*includeTrailingComma*/ false); + emitCommaList(node.arguments); write(")"); } } @@ -2372,7 +2404,7 @@ module ts { emit(node.expression); if (node.arguments) { write("("); - emitCommaList(node.arguments, /*includeTrailingComma*/ false); + emitCommaList(node.arguments); write(")"); } } @@ -2470,11 +2502,16 @@ module ts { function emitBinaryExpression(node: BinaryExpression) { - emit(node.left); - if (node.operator !== SyntaxKind.CommaToken) write(" "); - write(tokenToString(node.operator)); - write(" "); - emit(node.right); + if (node.operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + emitDestructuring(node); + } + else { + emit(node.left); + if (node.operator !== SyntaxKind.CommaToken) write(" "); + write(tokenToString(node.operator)); + write(" "); + emit(node.right); + } } function emitConditionalExpression(node: ConditionalExpression) { @@ -2494,6 +2531,9 @@ module ts { emitCaptureThisForNodeIfNecessary(node.parent); } emitLines(node.statements); + if (node.kind === SyntaxKind.ModuleBlock) { + emitTempDeclarations(/*newLine*/ true); + } decreaseIndent(); writeLine(); emitToken(SyntaxKind.CloseBraceToken, node.statements.end); @@ -2581,7 +2621,7 @@ module ts { emitToken(SyntaxKind.VarKeyword, endPos); } write(" "); - emitCommaList(node.declarations, /*includeTrailingComma*/ false); + emitCommaList(node.declarations); } if (node.initializer) { emit(node.initializer); @@ -2738,10 +2778,214 @@ module ts { emitEnd(node.name); } + function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, value?: Expression) { + var emitCount = 0; + // An exported declaration is actually emitted as an assignment (to a property on the module object), so + // temporary variables in an exported declaration need to have real declarations elsewhere + var isDeclaration = (root.kind === SyntaxKind.VariableDeclaration && !(root.flags & NodeFlags.Export)) || root.kind === SyntaxKind.Parameter; + if (root.kind === SyntaxKind.BinaryExpression) { + emitAssignmentExpression(root); + } + else { + emitBindingElement(root, value); + } + + function emitAssignment(name: Identifier, value: Expression) { + if (emitCount++) { + write(", "); + } + if (name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement)) { + emitModuleMemberName(name.parent); + } + else { + emit(name); + } + write(" = "); + emit(value); + } + + function ensureIdentifier(expr: Expression): Expression { + if (expr.kind !== SyntaxKind.Identifier) { + var identifier = createTempVariable(root); + if (!isDeclaration) { + recordTempDeclaration(identifier); + } + emitAssignment(identifier, expr); + expr = identifier; + } + return expr; + } + + function createVoidZero(): Expression { + var zero = createNode(SyntaxKind.NumericLiteral); + zero.text = "0"; + var result = createNode(SyntaxKind.PrefixUnaryExpression); + result.operator = SyntaxKind.VoidKeyword; + result.operand = zero; + return result; + } + + function createDefaultValueCheck(value: Expression, defaultValue: Expression): Expression { + // The value expression will be evaluated twice, so for anything but a simple identifier + // we need to generate a temporary variable + value = ensureIdentifier(value); + // Return the expression 'value === void 0 ? defaultValue : value' + var equals = createNode(SyntaxKind.BinaryExpression); + equals.left = value; + equals.operator = SyntaxKind.EqualsEqualsEqualsToken; + equals.right = createVoidZero(); + var cond = createNode(SyntaxKind.ConditionalExpression); + cond.condition = equals; + cond.whenTrue = defaultValue; + cond.whenFalse = value; + return cond; + } + + function createNumericLiteral(value: number) { + var node = createNode(SyntaxKind.NumericLiteral); + node.text = "" + value; + return node; + } + + function parenthesizeForAccess(expr: Expression): LeftHandSideExpression { + if (expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) { + return expr; + } + var node = createNode(SyntaxKind.ParenthesizedExpression); + node.expression = expr; + return node; + } + + function createPropertyAccess(object: Expression, propName: Identifier): Expression { + if (propName.kind !== SyntaxKind.Identifier) { + return createElementAccess(object, propName); + } + var node = createNode(SyntaxKind.PropertyAccessExpression); + node.expression = parenthesizeForAccess(object); + node.name = propName; + return node; + } + + function createElementAccess(object: Expression, index: Expression): Expression { + var node = createNode(SyntaxKind.ElementAccessExpression); + node.expression = parenthesizeForAccess(object); + node.argumentExpression = index; + return node; + } + + function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) { + var properties = target.properties; + if (properties.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + value = ensureIdentifier(value); + } + for (var i = 0; i < properties.length; i++) { + var p = properties[i]; + if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { + // TODO(andersh): Computed property support + var propName = ((p).name); + emitDestructuringAssignment((p).initializer || propName, createPropertyAccess(value, propName)); + } + } + } + + function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression) { + var elements = target.elements; + if (elements.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + value = ensureIdentifier(value); + } + for (var i = 0; i < elements.length; i++) { + var e = elements[i]; + if (e.kind !== SyntaxKind.OmittedExpression) { + emitDestructuringAssignment(e, createElementAccess(value, createNumericLiteral(i))); + } + } + } + + function emitDestructuringAssignment(target: Expression, value: Expression) { + if (target.kind === SyntaxKind.BinaryExpression && (target).operator === SyntaxKind.EqualsToken) { + value = createDefaultValueCheck(value,(target).right); + target = (target).left; + } + if (target.kind === SyntaxKind.ObjectLiteralExpression) { + emitObjectLiteralAssignment(target, value); + } + else if (target.kind === SyntaxKind.ArrayLiteralExpression) { + emitArrayLiteralAssignment(target, value); + } + else { + emitAssignment(target, value); + } + } + + function emitAssignmentExpression(root: BinaryExpression) { + var target = root.left; + var value = root.right; + if (root.parent.kind === SyntaxKind.ExpressionStatement) { + emitDestructuringAssignment(target, value); + } + else { + if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) { + write("("); + } + value = ensureIdentifier(value); + emitDestructuringAssignment(target, value); + write(", "); + emit(value); + if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) { + write(")"); + } + } + } + + function emitBindingElement(target: BindingElement, value: Expression) { + if (target.initializer) { + // Combine value and initializer + value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer; + } + else if (!value) { + // Use 'void 0' in absence of value and initializer + value = createVoidZero(); + } + if (isBindingPattern(target.name)) { + var pattern = target.name; + var elements = pattern.elements; + if (elements.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + value = ensureIdentifier(value); + } + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + if (pattern.kind === SyntaxKind.ObjectBindingPattern) { + // Rewrite element to a declaration with an initializer that fetches property + var propName = element.propertyName || element.name; + emitBindingElement(element, createPropertyAccess(value, propName)); + } + else if (element.kind !== SyntaxKind.OmittedExpression) { + // Rewrite element to a declaration that accesses array element at index i + emitBindingElement(element, createElementAccess(value, createNumericLiteral(i))); + } + } + } + else { + emitAssignment(target.name, value); + } + } + } + function emitVariableDeclaration(node: VariableDeclaration) { emitLeadingComments(node); - emitModuleMemberName(node); - emitOptional(" = ", node.initializer); + if (isBindingPattern(node.name)) { + emitDestructuring(node); + } + else { + emitModuleMemberName(node); + emitOptional(" = ", node.initializer); + } emitTrailingComments(node); } @@ -2758,32 +3002,57 @@ module ts { write("var "); } } - emitCommaList(node.declarations, /*includeTrailingComma*/ false); + emitCommaList(node.declarations); write(";"); emitTrailingComments(node); } function emitParameter(node: ParameterDeclaration) { emitLeadingComments(node); - emit(node.name); + if (isBindingPattern(node.name)) { + var name = createTempVariable(node); + if (!tempParameters) { + tempParameters = []; + } + tempParameters.push(name); + emit(name); + } + else { + emit(node.name); + } + // TODO(andersh): Enable ES6 code generation below + //if (node.propertyName) { + // emit(node.propertyName); + // write(": "); + //} + //emit(node.name); + //emitOptional(" = ", node.initializer); emitTrailingComments(node); } function emitDefaultValueAssignments(node: FunctionLikeDeclaration) { - forEach(node.parameters, param => { - if (param.initializer) { + var tempIndex = 0; + forEach(node.parameters, p => { + if (isBindingPattern(p.name)) { writeLine(); - emitStart(param); + write("var "); + emitDestructuring(p, tempParameters[tempIndex]); + write(";"); + tempIndex++; + } + else if (p.initializer) { + writeLine(); + emitStart(p); write("if ("); - emitNode(param.name); + emitNode(p.name); write(" === void 0)"); - emitEnd(param); + emitEnd(p); write(" { "); - emitStart(param); - emitNode(param.name); + emitStart(p); + emitNode(p.name); write(" = "); - emitNode(param.initializer); - emitEnd(param); + emitNode(p.initializer); + emitEnd(p); write("; }"); } }); @@ -2793,6 +3062,7 @@ module ts { if (hasRestParameters(node)) { var restIndex = node.parameters.length - 1; var restParam = node.parameters[restIndex]; + var tempName = createTempVariable(node, /*forLoopVariable*/ true).text; writeLine(); emitLeadingComments(restParam); emitStart(restParam); @@ -2804,22 +3074,22 @@ module ts { writeLine(); write("for ("); emitStart(restParam); - write("var _i = " + restIndex + ";"); + write("var " + tempName + " = " + restIndex + ";"); emitEnd(restParam); write(" "); emitStart(restParam); - write("_i < arguments.length;"); + write(tempName + " < arguments.length;"); emitEnd(restParam); write(" "); emitStart(restParam); - write("_i++"); + write(tempName + "++"); emitEnd(restParam); write(") {"); increaseIndent(); writeLine(); emitStart(restParam); emitNode(restParam.name); - write("[_i - " + restIndex + "] = arguments[_i];"); + write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];"); emitEnd(restParam); decreaseIndent(); writeLine(); @@ -2867,13 +3137,19 @@ module ts { increaseIndent(); write("("); if (node) { - emitCommaList(node.parameters, /*includeTrailingComma*/ false, node.parameters.length - (hasRestParameters(node) ? 1 : 0)); + emitCommaList(node.parameters, node.parameters.length - (hasRestParameters(node) ? 1 : 0)); } write(")"); decreaseIndent(); } function emitSignatureAndBody(node: FunctionLikeDeclaration) { + var saveTempCount = tempCount; + var saveTempVariables = tempVariables; + var saveTempParameters = tempParameters; + tempCount = 0; + tempVariables = undefined; + tempParameters = undefined; emitSignatureParameters(node); write(" {"); scopeEmitStart(node); @@ -2896,7 +3172,9 @@ module ts { write("return "); emitNode(node.body); emitEnd(node.body); - write("; "); + write(";"); + emitTempDeclarations(/*newLine*/ false); + write(" "); emitStart(node.body); write("}"); emitEnd(node.body); @@ -2913,11 +3191,12 @@ module ts { write(";"); emitTrailingComments(node.body); } + emitTempDeclarations(/*newLine*/ true); writeLine(); if (node.body.kind === SyntaxKind.Block) { emitLeadingCommentsOfPosition((node.body).statements.end); decreaseIndent(); - emitToken(SyntaxKind.CloseBraceToken, (node.body).statements.end); + emitToken(SyntaxKind.CloseBraceToken,(node.body).statements.end); } else { decreaseIndent(); @@ -2936,6 +3215,9 @@ module ts { emitEnd(node); write(";"); } + tempCount = saveTempCount; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; } function findInitialSuperCall(ctor: ConstructorDeclaration): ExpressionStatement { @@ -3139,6 +3421,12 @@ module ts { emitTrailingComments(node); function emitConstructorOfClass() { + var saveTempCount = tempCount; + var saveTempVariables = tempVariables; + var saveTempParameters = tempParameters; + tempCount = 0; + tempVariables = undefined; + tempParameters = undefined; // Emit the constructor overload pinned comments forEach(node.members, member => { if (member.kind === SyntaxKind.Constructor && !(member).body) { @@ -3187,6 +3475,7 @@ module ts { if (superCall) statements = statements.slice(1); emitLines(statements); } + emitTempDeclarations(/*newLine*/ true); writeLine(); if (ctor) { emitLeadingCommentsOfPosition((ctor.body).statements.end); @@ -3198,6 +3487,9 @@ module ts { if (ctor) { emitTrailingComments(ctor); } + tempCount = saveTempCount; + tempVariables = saveTempVariables; + tempParameters = saveTempParameters; } } @@ -3305,7 +3597,13 @@ module ts { emitEnd(node.name); write(") "); if (node.body.kind === SyntaxKind.ModuleBlock) { + var saveTempCount = tempCount; + var saveTempVariables = tempVariables; + tempCount = 0; + tempVariables = undefined; emit(node.body); + tempCount = saveTempCount; + tempVariables = saveTempVariables; } else { write("{"); @@ -3521,17 +3819,18 @@ module ts { if (!node) { return; } - if (node.flags & NodeFlags.Ambient) { return emitPinnedOrTripleSlashComments(node); } - // Check if the node can be emitted regardless of the ScriptTarget switch (node.kind) { case SyntaxKind.Identifier: return emitIdentifier(node); case SyntaxKind.Parameter: return emitParameter(node); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return emitMethod(node); case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: return emitAccessor(node); @@ -3559,12 +3858,18 @@ module ts { return emitTemplateSpan(node); case SyntaxKind.QualifiedName: return emitQualifiedName(node); + case SyntaxKind.ObjectBindingPattern: + return emitObjectBindingPattern(node); + case SyntaxKind.ArrayBindingPattern: + return emitArrayBindingPattern(node); case SyntaxKind.ArrayLiteralExpression: return emitArrayLiteral(node); case SyntaxKind.ObjectLiteralExpression: return emitObjectLiteral(node); case SyntaxKind.PropertyAssignment: return emitPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); case SyntaxKind.ComputedPropertyName: return emitComputedPropertyName(node); case SyntaxKind.PropertyAccessExpression: @@ -3659,29 +3964,6 @@ module ts { case SyntaxKind.SourceFile: return emitSourceFile(node); } - - // Emit node which needs to be emitted differently depended on ScriptTarget - if (compilerOptions.target < ScriptTarget.ES6) { - // Emit node down-level - switch (node.kind) { - case SyntaxKind.ShorthandPropertyAssignment: - return emitDownlevelShorthandPropertyAssignment(node); - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - return emitDownlevelMethod(node); - } - } - else { - // Emit node natively - Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Invalid ScriptTarget. We should emit as ES6 or above"); - switch (node.kind) { - case SyntaxKind.ShorthandPropertyAssignment: - return emitShorthandPropertyAssignment(node); - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - return emitMethod(node); - } - } } function hasDetachedComments(pos: number) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index bc91227f38..d406b938d4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -40,12 +40,8 @@ module ts { return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind)); } - function createRootNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags): Node { - var node = new (getNodeConstructor(kind))(); - node.pos = pos; - node.end = end; - node.flags = flags; - return node; + export function createNode(kind: SyntaxKind): Node { + return new (getNodeConstructor(kind))(); } export function getSourceFileOfNode(node: Node): SourceFile { @@ -140,6 +136,7 @@ module ts { // This list is a work in progress. Add missing node kinds to improve their error // spans. case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ModuleDeclaration: @@ -260,21 +257,19 @@ module ts { return child((node).name) || child((node).constraint); case SyntaxKind.Parameter: - return children(node.modifiers) || - child((node).dotDotDotToken) || - child((node).name) || - child((node).questionToken) || - child((node).type) || - child((node).initializer); case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: return children(node.modifiers) || - child((node).name) || - child((node).questionToken) || - child((node).type) || - child((node).initializer); + child((node).propertyName) || + child((node).dotDotDotToken) || + child((node).name) || + child((node).questionToken) || + child((node).type) || + child((node).initializer); case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: case SyntaxKind.CallSignature: @@ -315,6 +310,9 @@ module ts { return children((node).types); case SyntaxKind.ParenthesizedType: return child((node).type); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return children((node).elements); case SyntaxKind.ArrayLiteralExpression: return children((node).elements); case SyntaxKind.ObjectLiteralExpression: @@ -421,11 +419,6 @@ module ts { return child((node).name) || child((node).type) || child((node).block); - case SyntaxKind.VariableDeclaration: - return children(node.modifiers) || - child((node).name) || - child((node).type) || - child((node).initializer); case SyntaxKind.ClassDeclaration: return children(node.modifiers) || child((node).name) || @@ -506,6 +499,7 @@ module ts { export function isAnyFunction(node: Node): boolean { if (node) { switch (node.kind) { + case SyntaxKind.Constructor: case SyntaxKind.FunctionExpression: case SyntaxKind.FunctionDeclaration: case SyntaxKind.ArrowFunction: @@ -513,7 +507,14 @@ module ts { case SyntaxKind.MethodSignature: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - case SyntaxKind.Constructor: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: return true; } } @@ -522,11 +523,11 @@ module ts { } export function isFunctionBlock(node: Node) { - return node !== undefined && node.kind === SyntaxKind.Block && isAnyFunction(node.parent); + return node && node.kind === SyntaxKind.Block && isAnyFunction(node.parent); } export function isObjectLiteralMethod(node: Node) { - return node !== undefined && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; + return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; } export function getContainingFunction(node: Node): FunctionLikeDeclaration { @@ -646,7 +647,8 @@ module ts { case SyntaxKind.PropertySignature: case SyntaxKind.EnumMember: case SyntaxKind.PropertyAssignment: - return (parent).initializer === node; + case SyntaxKind.BindingElement: + return (parent).initializer === node; case SyntaxKind.ExpressionStatement: case SyntaxKind.IfStatement: case SyntaxKind.DoStatement: @@ -730,6 +732,10 @@ module ts { return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken; } + export function isBindingPattern(node: Node) { + return node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern; + } + export function isInAmbientContext(node: Node): boolean { while (node) { if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true; @@ -743,6 +749,7 @@ module ts { case SyntaxKind.TypeParameter: case SyntaxKind.Parameter: case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.PropertyAssignment: @@ -889,6 +896,8 @@ module ts { EnumMembers, // Members in enum declaration TypeReferences, // Type references in extends or implements clause VariableDeclarations, // Variable declarations in variable statement + ObjectBindingElements, // Binding elements in object binding list + ArrayBindingElements, // Binding elements in array binding list ArgumentExpressions, // Expressions in argument list ObjectLiteralMembers, // Members in object literal ArrayLiteralMembers, // Members in array literal @@ -918,6 +927,8 @@ module ts { case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected; case ParsingContext.TypeReferences: return Diagnostics.Type_reference_expected; case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected; + case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected; + case ParsingContext.ArrayBindingElements: return Diagnostics.Array_element_destructuring_pattern_expected; case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected; case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected; case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected; @@ -1087,17 +1098,20 @@ module ts { // Note: any errors at the end of the file that do not precede a regular node, should get // attached to the EOF token. var parseErrorBeforeNextFinishedNode = false; - var sourceFile = createRootNode(SyntaxKind.SourceFile, 0, sourceText.length, - fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0); + + var sourceFile = createNode(SyntaxKind.SourceFile, 0); + if (fileExtensionIs(filename, ".d.ts")) { + sourceFile.flags = NodeFlags.DeclarationFile; + } + sourceFile.end = sourceText.length; + sourceFile.filename = normalizePath(filename); + sourceFile.text = sourceText; sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition; sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter; sourceFile.getLineStarts = getLineStarts; sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics; - sourceFile.filename = normalizePath(filename); - sourceFile.text = sourceText; - sourceFile.referenceDiagnostics = []; sourceFile.parseDiagnostics = []; sourceFile.grammarDiagnostics = []; @@ -1559,11 +1573,16 @@ module ts { return token === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); case ParsingContext.ObjectLiteralMembers: return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName(); + case ParsingContext.ObjectBindingElements: + return isLiteralPropertyName(); case ParsingContext.TypeReferences: // We want to make sure that the "extends" in "extends foo" or the "implements" in // "implements foo" is not considered a type name. return isIdentifier() && !isNotHeritageClauseTypeName(); case ParsingContext.VariableDeclarations: + return isIdentifierOrPattern(); + case ParsingContext.ArrayBindingElements: + return token === SyntaxKind.CommaToken || isIdentifierOrPattern(); case ParsingContext.TypeParameters: return isIdentifier(); case ParsingContext.ArgumentExpressions: @@ -1612,6 +1631,7 @@ module ts { case ParsingContext.ClassMembers: case ParsingContext.EnumMembers: case ParsingContext.ObjectLiteralMembers: + case ParsingContext.ObjectBindingElements: return token === SyntaxKind.CloseBraceToken; case ParsingContext.SwitchClauseStatements: return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword; @@ -1627,10 +1647,11 @@ module ts { return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken; case ParsingContext.ArrayLiteralMembers: case ParsingContext.TupleElementTypes: + case ParsingContext.ArrayBindingElements: return token === SyntaxKind.CloseBracketToken; case ParsingContext.Parameters: // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery - return token === SyntaxKind.CloseParenToken || token === SyntaxKind.CloseBracketToken || token === SyntaxKind.OpenBraceToken; + return token === SyntaxKind.CloseParenToken || token === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; case ParsingContext.TypeArguments: // Tokens other than '>' are here for better error recovery return token === SyntaxKind.GreaterThanToken || token === SyntaxKind.OpenParenToken; @@ -1966,10 +1987,10 @@ module ts { } } - function parseParameterType(): TypeNode | StringLiteralExpression { + function parseParameterType(): TypeNode { if (parseOptional(SyntaxKind.ColonToken)) { return token === SyntaxKind.StringLiteral - ? parseLiteralNode(/*internName:*/ true) + ? parseLiteralNode(/*internName:*/ true) : parseType(); } @@ -1977,7 +1998,7 @@ module ts { } function isStartOfParameter(): boolean { - return token === SyntaxKind.DotDotDotToken || isIdentifier() || isModifier(token); + return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifier(token); } function setModifiers(node: Node, modifiers: ModifiersArray) { @@ -1996,9 +2017,7 @@ module ts { // [+GeneratorParameter]BindingIdentifier[Yield]Initializer[In]opt // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt - node.name = inGeneratorParameterContext() - ? doInYieldContext(parseIdentifier) - : parseIdentifier(); + node.name = inGeneratorParameterContext() ? doInYieldContext(parseIdentifierOrPattern) : parseIdentifierOrPattern(); if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) { // in cases like @@ -2014,9 +2033,7 @@ module ts { node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); node.type = parseParameterType(); - node.initializer = inGeneratorParameterContext() - ? doOutsideOfYieldContext(parseParameterInitializer) - : parseParameterInitializer(); + node.initializer = inGeneratorParameterContext() ? doOutsideOfYieldContext(parseParameterInitializer) : parseParameterInitializer(); // Do not check for initializers in an ambient context for parameters. This is not // a grammar error because the grammar allows arbitrary call signatures in @@ -3841,20 +3858,81 @@ module ts { // DECLARATIONS + function parseBindingElement(context: ParsingContext): BindingElement { + if (context === ParsingContext.ArrayBindingElements && token === SyntaxKind.CommaToken) { + return createNode(SyntaxKind.OmittedExpression); + } + var node = createNode(SyntaxKind.BindingElement); + if (context === ParsingContext.ObjectBindingElements) { + // TODO(andersh): Handle computed properties + var id = parsePropertyName(); + if (id.kind === SyntaxKind.Identifier && token !== SyntaxKind.ColonToken) { + node.name = id; + } + else { + parseExpected(SyntaxKind.ColonToken); + node.propertyName = id; + node.name = parseIdentifierOrPattern(); + } + } + else { + node.name = parseIdentifierOrPattern(); + } + node.initializer = parseInitializer(/*inParameter*/ false); + return finishNode(node); + } + + function parseBindingList(context: ParsingContext): NodeArray { + return parseDelimitedList(context, () => parseBindingElement(context)); + } + + function parseObjectBindingPattern(): BindingPattern { + var node = createNode(SyntaxKind.ObjectBindingPattern); + parseExpected(SyntaxKind.OpenBraceToken); + node.elements = parseBindingList(ParsingContext.ObjectBindingElements); + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + + function parseArrayBindingPattern(): BindingPattern { + var node = createNode(SyntaxKind.ArrayBindingPattern); + parseExpected(SyntaxKind.OpenBracketToken); + node.elements = parseBindingList(ParsingContext.ArrayBindingElements); + parseExpected(SyntaxKind.CloseBracketToken); + return finishNode(node); + } + + function isIdentifierOrPattern() { + return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken || isIdentifier(); + } + + function parseIdentifierOrPattern(): Identifier | BindingPattern { + if (token === SyntaxKind.OpenBracketToken) { + return parseArrayBindingPattern(); + } + if (token === SyntaxKind.OpenBraceToken) { + return parseObjectBindingPattern(); + } + return parseIdentifier(); + } + function parseVariableDeclaration(): VariableDeclaration { var node = createNode(SyntaxKind.VariableDeclaration); - node.name = parseIdentifier(); + node.name = parseIdentifierOrPattern(); node.type = parseTypeAnnotation(); node.initializer = parseInitializer(/*inParameter*/ false); return finishNode(node); } - function setFlag(array: NodeArray, flag: NodeFlags): NodeArray { - for (var i = 0, n = array.length; i < n; i++) { - array[i].flags |= flag; + function setFlag(nodes: NodeArray, flag: NodeFlags): NodeArray { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + node.flags |= flag; + if (node.name && isBindingPattern(node.name)) { + setFlag((node.name).elements, flag); + } } - - return array; + return nodes; } function parseVariableDeclarationList(): NodeArray { @@ -4562,6 +4640,7 @@ module ts { case SyntaxKind.EnumDeclaration: return checkEnumDeclaration(node); case SyntaxKind.BinaryExpression: return checkBinaryExpression(node); + case SyntaxKind.BindingElement: return checkBindingElement(node); case SyntaxKind.CatchClause: return checkCatchClause(node); case SyntaxKind.ClassDeclaration: return checkClassDeclaration(node); case SyntaxKind.ComputedPropertyName: return checkComputedPropertyName(node); @@ -5386,7 +5465,7 @@ module ts { // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a // strict mode FunctionLikeDeclaration or FunctionExpression(13.1) if (node.parserContextFlags & ParserContextFlags.StrictMode && isEvalOrArgumentsIdentifier(node.name)) { - return reportInvalidUseInStrictMode(node.name); + return reportInvalidUseInStrictMode(node.name); } } @@ -5658,18 +5737,38 @@ module ts { return checkTypeArguments(node.typeArguments); } - function checkVariableDeclaration(node: VariableDeclaration) { - if (inAmbientContext && node.initializer) { - var equalsPos = node.type ? skipTrivia(sourceText, node.type.end) : skipTrivia(sourceText, node.name.end); - return grammarErrorAtPos(equalsPos, "=".length, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + function checkBindingElement(node: BindingElement) { + if (node.parserContextFlags & ParserContextFlags.StrictMode && isEvalOrArgumentsIdentifier(node.name)) { + // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code + // and its Identifier is eval or arguments + return reportInvalidUseInStrictMode(node.name); } - if (!inAmbientContext && !node.initializer && isConst(node)) { - return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized); + } + + function checkVariableDeclaration(node: VariableDeclaration) { + if (inAmbientContext) { + if (isBindingPattern(node.name)) { + return grammarErrorOnNode(node, Diagnostics.Destructuring_declarations_are_not_allowed_in_ambient_contexts); + } + if (node.initializer) { + // Error on equals token which immediate precedes the initializer + return grammarErrorAtPos(node.initializer.pos - 1, 1, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); + } + } + else { + if (!node.initializer) { + if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) { + return grammarErrorOnNode(node, Diagnostics.A_destructuring_declaration_must_have_an_initializer); + } + if (isConst(node)) { + return grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized); + } + } } if (node.parserContextFlags & ParserContextFlags.StrictMode && isEvalOrArgumentsIdentifier(node.name)) { // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code // and its Identifier is eval or arguments - return reportInvalidUseInStrictMode(node.name); + return reportInvalidUseInStrictMode(node.name); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 44108c347a..19baf05240 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -167,6 +167,10 @@ module ts { TupleType, UnionType, ParenthesizedType, + // Binding patterns + ObjectBindingPattern, + ArrayBindingPattern, + BindingElement, // Expression ArrayLiteralExpression, ObjectLiteralExpression, @@ -353,7 +357,8 @@ module ts { } export type EntityName = Identifier | QualifiedName; - export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName; + + export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName | BindingPattern; export interface Declaration extends Node { _declarationBrand: any; @@ -378,39 +383,43 @@ module ts { type?: TypeNode; } + // SyntaxKind.VariableDeclaration export interface VariableDeclaration extends Declaration { - name: Identifier; - type?: TypeNode; - initializer?: Expression; + name: Identifier | BindingPattern; // Declared variable name + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer } + // SyntaxKind.Parameter export interface ParameterDeclaration extends Declaration { - dotDotDotToken?: Node; - name: Identifier; - questionToken?: Node; - type?: TypeNode | StringLiteralExpression; - initializer?: Expression; + dotDotDotToken?: Node; // Present on rest parameter + name: Identifier | BindingPattern; // Declared parameter name + questionToken?: Node; // Present on optional parameter + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer } + // SyntaxKind.BindingElement + export interface BindingElement extends Declaration { + propertyName?: Identifier; // Binding property name (in object binding pattern) + dotDotDotToken?: Node; // Present on rest binding element + name: Identifier | BindingPattern; // Declared binding element name + initializer?: Expression; // Optional initializer + } + + // SyntaxKind.Property export interface PropertyDeclaration extends Declaration, ClassElement { - _propertyDeclarationBrand: any; - questionToken?: Node; - type?: TypeNode; - initializer?: Expression; + name: DeclarationName; // Declared property name + questionToken?: Node; // Present on optional property + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer } - export type VariableOrParameterDeclaration = VariableDeclaration | ParameterDeclaration; - export type VariableOrParameterOrPropertyDeclaration = VariableOrParameterDeclaration | PropertyDeclaration; - export interface ObjectLiteralElement extends Declaration { _objectLiteralBrandBrand: any; } - export interface ShorthandPropertyAssignment extends ObjectLiteralElement { - name: Identifier; - questionToken?: Node; - } - + // SyntaxKind.PropertyAssignment export interface PropertyAssignment extends ObjectLiteralElement { _propertyAssignmentBrand: any; name: DeclarationName; @@ -418,6 +427,32 @@ module ts { initializer: Expression; } + // SyntaxKind.ShorthandPropertyAssignment + export interface ShorthandPropertyAssignment extends ObjectLiteralElement { + name: Identifier; + questionToken?: Node; + } + + // SyntaxKind.VariableDeclaration + // SyntaxKind.Parameter + // SyntaxKind.BindingElement + // SyntaxKind.Property + // SyntaxKind.PropertyAssignment + // SyntaxKind.ShorthandPropertyAssignment + // SyntaxKind.EnumMember + export interface VariableLikeDeclaration extends Declaration { + propertyName?: Identifier; + dotDotDotToken?: Node; + name: DeclarationName; + questionToken?: Node; + type?: TypeNode; + initializer?: Expression; + } + + export interface BindingPattern extends Node { + elements: NodeArray; + } + /** * Several node kinds share function-like features such as a signature, * a name, and a body. These nodes should extend FunctionLikeDeclaration. @@ -505,6 +540,8 @@ module ts { type: TypeNode; } + export interface StringLiteralTypeNode extends LiteralExpression, TypeNode { } + // Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing. // Consider 'Expression'. Without the brand, 'Expression' is actually no different // (structurally) than 'Node'. Because of this you can pass any Node to a function that @@ -1034,13 +1071,14 @@ module ts { hasSemanticErrors(sourceFile?: SourceFile): boolean; isDeclarationVisible(node: Declaration): boolean; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; - writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableOrParameterDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; + writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult; isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant getConstantValue(node: PropertyAccessExpression | ElementAccessExpression): number; isEmitBlocked(sourceFile?: SourceFile): boolean; + isUnknownIdentifier(location: Node, name: string): boolean; } export const enum SymbolFlags { @@ -1061,35 +1099,33 @@ module ts { Constructor = 0x00004000, // Constructor GetAccessor = 0x00008000, // Get accessor SetAccessor = 0x00010000, // Set accessor - CallSignature = 0x00020000, // Call signature - ConstructSignature = 0x00040000, // Construct signature - IndexSignature = 0x00080000, // Index signature - TypeParameter = 0x00100000, // Type parameter - TypeAlias = 0x00200000, // Type alias + Signature = 0x00020000, // Call, construct, or index signature + TypeParameter = 0x00040000, // Type parameter + TypeAlias = 0x00080000, // Type alias // Export markers (see comment in declareModuleMember in binder) - ExportValue = 0x00400000, // Exported value marker - ExportType = 0x00800000, // Exported type marker - ExportNamespace = 0x01000000, // Exported namespace marker - Import = 0x02000000, // Import - Instantiated = 0x04000000, // Instantiated symbol - Merged = 0x08000000, // Merged symbol (created during program binding) - Transient = 0x10000000, // Transient symbol (created during type check) - Prototype = 0x20000000, // Prototype property (no source representation) - UnionProperty = 0x40000000, // Property in union type + ExportValue = 0x00100000, // Exported value marker + ExportType = 0x00200000, // Exported type marker + ExportNamespace = 0x00400000, // Exported namespace marker + Import = 0x00800000, // Import + Instantiated = 0x01000000, // Instantiated symbol + Merged = 0x02000000, // Merged symbol (created during program binding) + Transient = 0x04000000, // Transient symbol (created during type check) + Prototype = 0x08000000, // Prototype property (no source representation) + UnionProperty = 0x10000000, // Property in union type + Optional = 0x20000000, // Optional property - Enum = RegularEnum | ConstEnum, + Enum = RegularEnum | ConstEnum, Variable = FunctionScopedVariable | BlockScopedVariable, Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias, Namespace = ValueModule | NamespaceModule, Module = ValueModule | NamespaceModule, Accessor = GetAccessor | SetAccessor, - Signature = CallSignature | ConstructSignature | IndexSignature, - // Variables can be redeclared, but can not redeclare a block-scoped declaration with the + // Variables can be redeclared, but can not redeclare a block-scoped declaration with the // same name, or any other value that is not a variable, e.g. ValueModule or Class - FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable, + FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable, // Block-scoped declarations are not allowed to be re-declared // they can not merge with anything in the value space @@ -1198,6 +1234,7 @@ module ts { Union = 0x00004000, // Union Anonymous = 0x00008000, // Anonymous FromSignature = 0x00010000, // Created for signature assignment check + Unwidened = 0x00020000, // Unwidened type (is or contains Undefined or Null type) Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null, StringLike = String | StringLiteral, diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 0840ccbf7d..29b2db72fc 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -37,26 +37,50 @@ module ts.NavigationBar { return indent; } - + function getChildNodes(nodes: Node[]): Node[] { - var childNodes: Node[] = []; + var childNodes: Node[] = []; - for (var i = 0, n = nodes.length; i < n; i++) { - var node = nodes[i]; - - if (node.kind === SyntaxKind.ClassDeclaration || - node.kind === SyntaxKind.EnumDeclaration || - node.kind === SyntaxKind.InterfaceDeclaration || - node.kind === SyntaxKind.ModuleDeclaration || - node.kind === SyntaxKind.FunctionDeclaration) { - - childNodes.push(node); - } - else if (node.kind === SyntaxKind.VariableStatement) { - childNodes.push.apply(childNodes, (node).declarations); + function visit(node: Node) { + switch (node.kind) { + case SyntaxKind.VariableStatement: + forEach((node).declarations, visit); + break; + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + forEach((node).elements, visit); + break; + case SyntaxKind.VariableDeclaration: + if (isBindingPattern(node)) { + visit((node).name); + break; + } + // Fall through + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.FunctionDeclaration: + childNodes.push(node); } } + //for (var i = 0, n = nodes.length; i < n; i++) { + // var node = nodes[i]; + + // if (node.kind === SyntaxKind.ClassDeclaration || + // node.kind === SyntaxKind.EnumDeclaration || + // node.kind === SyntaxKind.InterfaceDeclaration || + // node.kind === SyntaxKind.ModuleDeclaration || + // node.kind === SyntaxKind.FunctionDeclaration) { + + // childNodes.push(node); + // } + // else if (node.kind === SyntaxKind.VariableStatement) { + // childNodes.push.apply(childNodes, (node).declarations); + // } + //} + forEach(nodes, visit); return sortNodes(childNodes); } @@ -200,6 +224,9 @@ module ts.NavigationBar { function createChildItem(node: Node): ts.NavigationBarItem { switch (node.kind) { case SyntaxKind.Parameter: + if (isBindingPattern((node).name)) { + break; + } if ((node.flags & NodeFlags.Modifier) === 0) { return undefined; } @@ -235,6 +262,9 @@ module ts.NavigationBar { return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.functionElement); case SyntaxKind.VariableDeclaration: + if (isBindingPattern((node).name)) { + break; + } if (isConst(node)) { return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.constElement); } diff --git a/src/services/services.ts b/src/services/services.ts index 54c17f0101..759d2bac2c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -806,6 +806,8 @@ module ts { // fall through case SyntaxKind.Constructor: case SyntaxKind.VariableStatement: + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ModuleBlock: forEachChild(node, visit); break; @@ -823,6 +825,11 @@ module ts { } // fall through case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: + if (isBindingPattern((node).name)) { + forEachChild((node).name, visit); + break; + } case SyntaxKind.EnumMember: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -4746,6 +4753,7 @@ module ts { switch (node.kind) { case SyntaxKind.Parameter: case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.PropertyAssignment: diff --git a/tests/baselines/reference/assignmentLHSIsValue.errors.txt b/tests/baselines/reference/assignmentLHSIsValue.errors.txt index ea4908f731..f019bfdf6c 100644 --- a/tests/baselines/reference/assignmentLHSIsValue.errors.txt +++ b/tests/baselines/reference/assignmentLHSIsValue.errors.txt @@ -19,7 +19,8 @@ tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(2 tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(30,1): error TS2364: Invalid left-hand side of assignment expression. tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(31,1): error TS2364: Invalid left-hand side of assignment expression. tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(32,1): error TS2364: Invalid left-hand side of assignment expression. -tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(38,1): error TS2364: Invalid left-hand side of assignment expression. +tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(38,2): error TS2364: Invalid left-hand side of assignment expression. +tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(38,6): error TS2364: Invalid left-hand side of assignment expression. tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(54,1): error TS2364: Invalid left-hand side of assignment expression. tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(57,1): error TS2364: Invalid left-hand side of assignment expression. tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(58,1): error TS2364: Invalid left-hand side of assignment expression. @@ -37,7 +38,7 @@ tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(6 tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(70,1): error TS2364: Invalid left-hand side of assignment expression. -==== tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts (37 errors) ==== +==== tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts (38 errors) ==== // expected error for all the LHS of assignments var value; @@ -108,7 +109,9 @@ tests/cases/conformance/expressions/assignmentOperator/assignmentLHSIsValue.ts(7 // array literals ['', ''] = value; - ~~~~~~~~ + ~~ +!!! error TS2364: Invalid left-hand side of assignment expression. + ~~ !!! error TS2364: Invalid left-hand side of assignment expression. // super diff --git a/tests/baselines/reference/collisionRestParameterArrowFunctions.errors.txt b/tests/baselines/reference/collisionRestParameterArrowFunctions.errors.txt deleted file mode 100644 index 5c585e5a6c..0000000000 --- a/tests/baselines/reference/collisionRestParameterArrowFunctions.errors.txt +++ /dev/null @@ -1,19 +0,0 @@ -tests/cases/compiler/collisionRestParameterArrowFunctions.ts(1,11): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - - -==== tests/cases/compiler/collisionRestParameterArrowFunctions.ts (1 errors) ==== - var f1 = (_i: number, ...restParameters) => { //_i is error - ~~~~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i = 10; // no error - } - var f1NoError = (_i: number) => { // no error - var _i = 10; // no error - } - - var f2 = (...restParameters) => { - var _i = 10; // No Error - } - var f2NoError = () => { - var _i = 10; // no error - } \ No newline at end of file diff --git a/tests/baselines/reference/collisionRestParameterArrowFunctions.js b/tests/baselines/reference/collisionRestParameterArrowFunctions.js index cc8dc337b8..39d449555d 100644 --- a/tests/baselines/reference/collisionRestParameterArrowFunctions.js +++ b/tests/baselines/reference/collisionRestParameterArrowFunctions.js @@ -16,8 +16,8 @@ var f2NoError = () => { //// [collisionRestParameterArrowFunctions.js] var f1 = function (_i) { var restParameters = []; - for (var _i = 1; _i < arguments.length; _i++) { - restParameters[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + restParameters[_a - 1] = arguments[_a]; } var _i = 10; // no error }; @@ -26,8 +26,8 @@ var f1NoError = function (_i) { }; var f2 = function () { var restParameters = []; - for (var _i = 0; _i < arguments.length; _i++) { - restParameters[_i - 0] = arguments[_i]; + for (var _a = 0; _a < arguments.length; _a++) { + restParameters[_a - 0] = arguments[_a]; } var _i = 10; // No Error }; diff --git a/tests/baselines/reference/collisionRestParameterArrowFunctions.types b/tests/baselines/reference/collisionRestParameterArrowFunctions.types new file mode 100644 index 0000000000..f2316c9958 --- /dev/null +++ b/tests/baselines/reference/collisionRestParameterArrowFunctions.types @@ -0,0 +1,34 @@ +=== tests/cases/compiler/collisionRestParameterArrowFunctions.ts === +var f1 = (_i: number, ...restParameters) => { //_i is error +>f1 : (_i: number, ...restParameters: any[]) => void +>(_i: number, ...restParameters) => { //_i is error var _i = 10; // no error} : (_i: number, ...restParameters: any[]) => void +>_i : number +>restParameters : any[] + + var _i = 10; // no error +>_i : number +} +var f1NoError = (_i: number) => { // no error +>f1NoError : (_i: number) => void +>(_i: number) => { // no error var _i = 10; // no error} : (_i: number) => void +>_i : number + + var _i = 10; // no error +>_i : number +} + +var f2 = (...restParameters) => { +>f2 : (...restParameters: any[]) => void +>(...restParameters) => { var _i = 10; // No Error} : (...restParameters: any[]) => void +>restParameters : any[] + + var _i = 10; // No Error +>_i : number +} +var f2NoError = () => { +>f2NoError : () => void +>() => { var _i = 10; // no error} : () => void + + var _i = 10; // no error +>_i : number +} diff --git a/tests/baselines/reference/collisionRestParameterClassConstructor.errors.txt b/tests/baselines/reference/collisionRestParameterClassConstructor.errors.txt deleted file mode 100644 index a30b6d11d4..0000000000 --- a/tests/baselines/reference/collisionRestParameterClassConstructor.errors.txt +++ /dev/null @@ -1,78 +0,0 @@ -tests/cases/compiler/collisionRestParameterClassConstructor.ts(3,17): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. -tests/cases/compiler/collisionRestParameterClassConstructor.ts(25,17): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. -tests/cases/compiler/collisionRestParameterClassConstructor.ts(45,17): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - - -==== tests/cases/compiler/collisionRestParameterClassConstructor.ts (3 errors) ==== - // Constructors - class c1 { - constructor(_i: number, ...restParameters) { //_i is error - ~~~~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i = 10; // no error - } - } - class c1NoError { - constructor(_i: number) { // no error - var _i = 10; // no error - } - } - - class c2 { - constructor(...restParameters) { - var _i = 10; // no error - } - } - class c2NoError { - constructor() { - var _i = 10; // no error - } - } - - class c3 { - constructor(public _i: number, ...restParameters) { //_i is error - ~~~~~~~~~~~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i = 10; // no error - } - } - class c3NoError { - constructor(public _i: number) { // no error - var _i = 10; // no error - } - } - - declare class c4 { - constructor(_i: number, ...restParameters); // No error - no code gen - } - declare class c4NoError { - constructor(_i: number); // no error - } - - class c5 { - constructor(_i: number, ...rest); // no codegen no error - constructor(_i: string, ...rest); // no codegen no error - constructor(_i: any, ...rest) { // error - ~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i: any; // no error - } - } - - class c5NoError { - constructor(_i: number); // no error - constructor(_i: string); // no error - constructor(_i: any) { // no error - var _i: any; // no error - } - } - - declare class c6 { - constructor(_i: number, ...rest); // no codegen no error - constructor(_i: string, ...rest); // no codegen no error - } - - declare class c6NoError { - constructor(_i: number); // no error - constructor(_i: string); // no error - } \ No newline at end of file diff --git a/tests/baselines/reference/collisionRestParameterClassConstructor.js b/tests/baselines/reference/collisionRestParameterClassConstructor.js index 02c7ada9df..fc6e400668 100644 --- a/tests/baselines/reference/collisionRestParameterClassConstructor.js +++ b/tests/baselines/reference/collisionRestParameterClassConstructor.js @@ -71,8 +71,8 @@ declare class c6NoError { var c1 = (function () { function c1(_i) { var restParameters = []; - for (var _i = 1; _i < arguments.length; _i++) { - restParameters[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + restParameters[_a - 1] = arguments[_a]; } var _i = 10; // no error } @@ -87,8 +87,8 @@ var c1NoError = (function () { var c2 = (function () { function c2() { var restParameters = []; - for (var _i = 0; _i < arguments.length; _i++) { - restParameters[_i - 0] = arguments[_i]; + for (var _a = 0; _a < arguments.length; _a++) { + restParameters[_a - 0] = arguments[_a]; } var _i = 10; // no error } @@ -103,8 +103,8 @@ var c2NoError = (function () { var c3 = (function () { function c3(_i) { var restParameters = []; - for (var _i = 1; _i < arguments.length; _i++) { - restParameters[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + restParameters[_a - 1] = arguments[_a]; } this._i = _i; var _i = 10; // no error @@ -121,8 +121,8 @@ var c3NoError = (function () { var c5 = (function () { function c5(_i) { var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + rest[_a - 1] = arguments[_a]; } var _i; // no error } diff --git a/tests/baselines/reference/collisionRestParameterClassConstructor.types b/tests/baselines/reference/collisionRestParameterClassConstructor.types new file mode 100644 index 0000000000..d0ceb9e074 --- /dev/null +++ b/tests/baselines/reference/collisionRestParameterClassConstructor.types @@ -0,0 +1,137 @@ +=== tests/cases/compiler/collisionRestParameterClassConstructor.ts === +// Constructors +class c1 { +>c1 : c1 + + constructor(_i: number, ...restParameters) { //_i is error +>_i : number +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } +} +class c1NoError { +>c1NoError : c1NoError + + constructor(_i: number) { // no error +>_i : number + + var _i = 10; // no error +>_i : number + } +} + +class c2 { +>c2 : c2 + + constructor(...restParameters) { +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } +} +class c2NoError { +>c2NoError : c2NoError + + constructor() { + var _i = 10; // no error +>_i : number + } +} + +class c3 { +>c3 : c3 + + constructor(public _i: number, ...restParameters) { //_i is error +>_i : number +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } +} +class c3NoError { +>c3NoError : c3NoError + + constructor(public _i: number) { // no error +>_i : number + + var _i = 10; // no error +>_i : number + } +} + +declare class c4 { +>c4 : c4 + + constructor(_i: number, ...restParameters); // No error - no code gen +>_i : number +>restParameters : any[] +} +declare class c4NoError { +>c4NoError : c4NoError + + constructor(_i: number); // no error +>_i : number +} + +class c5 { +>c5 : c5 + + constructor(_i: number, ...rest); // no codegen no error +>_i : number +>rest : any[] + + constructor(_i: string, ...rest); // no codegen no error +>_i : string +>rest : any[] + + constructor(_i: any, ...rest) { // error +>_i : any +>rest : any[] + + var _i: any; // no error +>_i : any + } +} + +class c5NoError { +>c5NoError : c5NoError + + constructor(_i: number); // no error +>_i : number + + constructor(_i: string); // no error +>_i : string + + constructor(_i: any) { // no error +>_i : any + + var _i: any; // no error +>_i : any + } +} + +declare class c6 { +>c6 : c6 + + constructor(_i: number, ...rest); // no codegen no error +>_i : number +>rest : any[] + + constructor(_i: string, ...rest); // no codegen no error +>_i : string +>rest : any[] +} + +declare class c6NoError { +>c6NoError : c6NoError + + constructor(_i: number); // no error +>_i : number + + constructor(_i: string); // no error +>_i : string +} diff --git a/tests/baselines/reference/collisionRestParameterClassMethod.errors.txt b/tests/baselines/reference/collisionRestParameterClassMethod.errors.txt deleted file mode 100644 index ac3fb1a556..0000000000 --- a/tests/baselines/reference/collisionRestParameterClassMethod.errors.txt +++ /dev/null @@ -1,47 +0,0 @@ -tests/cases/compiler/collisionRestParameterClassMethod.ts(2,16): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. -tests/cases/compiler/collisionRestParameterClassMethod.ts(10,15): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - - -==== tests/cases/compiler/collisionRestParameterClassMethod.ts (2 errors) ==== - class c1 { - public foo(_i: number, ...restParameters) { //_i is error - ~~~~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i = 10; // no error - } - public fooNoError(_i: number) { // no error - var _i = 10; // no error - } - public f4(_i: number, ...rest); // no codegen no error - public f4(_i: string, ...rest); // no codegen no error - public f4(_i: any, ...rest) { // error - ~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i: any; // no error - } - - public f4NoError(_i: number); // no error - public f4NoError(_i: string); // no error - public f4NoError(_i: any) { // no error - var _i: any; // no error - } - } - - declare class c2 { - public foo(_i: number, ...restParameters); // No error - no code gen - public fooNoError(_i: number); // no error - - public f4(_i: number, ...rest); // no codegen no error - public f4(_i: string, ...rest); // no codegen no error - public f4NoError(_i: number); // no error - public f4NoError(_i: string); // no error - } - - class c3 { - public foo(...restParameters) { - var _i = 10; // no error - } - public fooNoError() { - var _i = 10; // no error - } - } \ No newline at end of file diff --git a/tests/baselines/reference/collisionRestParameterClassMethod.js b/tests/baselines/reference/collisionRestParameterClassMethod.js index 326ad0c424..e3471c85f1 100644 --- a/tests/baselines/reference/collisionRestParameterClassMethod.js +++ b/tests/baselines/reference/collisionRestParameterClassMethod.js @@ -44,8 +44,8 @@ var c1 = (function () { } c1.prototype.foo = function (_i) { var restParameters = []; - for (var _i = 1; _i < arguments.length; _i++) { - restParameters[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + restParameters[_a - 1] = arguments[_a]; } var _i = 10; // no error }; @@ -54,8 +54,8 @@ var c1 = (function () { }; c1.prototype.f4 = function (_i) { var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + rest[_a - 1] = arguments[_a]; } var _i; // no error }; @@ -69,8 +69,8 @@ var c3 = (function () { } c3.prototype.foo = function () { var restParameters = []; - for (var _i = 0; _i < arguments.length; _i++) { - restParameters[_i - 0] = arguments[_i]; + for (var _a = 0; _a < arguments.length; _a++) { + restParameters[_a - 0] = arguments[_a]; } var _i = 10; // no error }; diff --git a/tests/baselines/reference/collisionRestParameterClassMethod.types b/tests/baselines/reference/collisionRestParameterClassMethod.types new file mode 100644 index 0000000000..2a4c23ae5a --- /dev/null +++ b/tests/baselines/reference/collisionRestParameterClassMethod.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/collisionRestParameterClassMethod.ts === +class c1 { +>c1 : c1 + + public foo(_i: number, ...restParameters) { //_i is error +>foo : (_i: number, ...restParameters: any[]) => void +>_i : number +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } + public fooNoError(_i: number) { // no error +>fooNoError : (_i: number) => void +>_i : number + + var _i = 10; // no error +>_i : number + } + public f4(_i: number, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : number +>rest : any[] + + public f4(_i: string, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : string +>rest : any[] + + public f4(_i: any, ...rest) { // error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : any +>rest : any[] + + var _i: any; // no error +>_i : any + } + + public f4NoError(_i: number); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : number + + public f4NoError(_i: string); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : string + + public f4NoError(_i: any) { // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : any + + var _i: any; // no error +>_i : any + } +} + +declare class c2 { +>c2 : c2 + + public foo(_i: number, ...restParameters); // No error - no code gen +>foo : (_i: number, ...restParameters: any[]) => any +>_i : number +>restParameters : any[] + + public fooNoError(_i: number); // no error +>fooNoError : (_i: number) => any +>_i : number + + public f4(_i: number, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : number +>rest : any[] + + public f4(_i: string, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : string +>rest : any[] + + public f4NoError(_i: number); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : number + + public f4NoError(_i: string); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : string +} + +class c3 { +>c3 : c3 + + public foo(...restParameters) { +>foo : (...restParameters: any[]) => void +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } + public fooNoError() { +>fooNoError : () => void + + var _i = 10; // no error +>_i : number + } +} diff --git a/tests/baselines/reference/collisionRestParameterFunction.errors.txt b/tests/baselines/reference/collisionRestParameterFunction.errors.txt deleted file mode 100644 index 88a98b9c77..0000000000 --- a/tests/baselines/reference/collisionRestParameterFunction.errors.txt +++ /dev/null @@ -1,42 +0,0 @@ -tests/cases/compiler/collisionRestParameterFunction.ts(2,13): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. -tests/cases/compiler/collisionRestParameterFunction.ts(21,13): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - - -==== tests/cases/compiler/collisionRestParameterFunction.ts (2 errors) ==== - // Functions - function f1(_i: number, ...restParameters) { //_i is error - ~~~~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i = 10; // no error - } - function f1NoError(_i: number) { // no error - var _i = 10; // no error - } - - declare function f2(_i: number, ...restParameters); // no error - no code gen - declare function f2NoError(_i: number); // no error - - function f3(...restParameters) { - var _i = 10; // no error - } - function f3NoError() { - var _i = 10; // no error - } - - function f4(_i: number, ...rest); // no codegen no error - function f4(_i: string, ...rest); // no codegen no error - function f4(_i: any, ...rest) { // error - ~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - } - - function f4NoError(_i: number); // no error - function f4NoError(_i: string); // no error - function f4NoError(_i: any) { // no error - } - - declare function f5(_i: number, ...rest); // no codegen no error - declare function f5(_i: string, ...rest); // no codegen no error - - declare function f6(_i: number); // no codegen no error - declare function f6(_i: string); // no codegen no error \ No newline at end of file diff --git a/tests/baselines/reference/collisionRestParameterFunction.js b/tests/baselines/reference/collisionRestParameterFunction.js index c81dbb0f8d..8660e8f5db 100644 --- a/tests/baselines/reference/collisionRestParameterFunction.js +++ b/tests/baselines/reference/collisionRestParameterFunction.js @@ -37,8 +37,8 @@ declare function f6(_i: string); // no codegen no error // Functions function f1(_i) { var restParameters = []; - for (var _i = 1; _i < arguments.length; _i++) { - restParameters[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + restParameters[_a - 1] = arguments[_a]; } var _i = 10; // no error } @@ -47,8 +47,8 @@ function f1NoError(_i) { } function f3() { var restParameters = []; - for (var _i = 0; _i < arguments.length; _i++) { - restParameters[_i - 0] = arguments[_i]; + for (var _a = 0; _a < arguments.length; _a++) { + restParameters[_a - 0] = arguments[_a]; } var _i = 10; // no error } @@ -57,8 +57,8 @@ function f3NoError() { } function f4(_i) { var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + rest[_a - 1] = arguments[_a]; } } function f4NoError(_i) { diff --git a/tests/baselines/reference/collisionRestParameterFunction.types b/tests/baselines/reference/collisionRestParameterFunction.types new file mode 100644 index 0000000000..f0d8abeac9 --- /dev/null +++ b/tests/baselines/reference/collisionRestParameterFunction.types @@ -0,0 +1,88 @@ +=== tests/cases/compiler/collisionRestParameterFunction.ts === +// Functions +function f1(_i: number, ...restParameters) { //_i is error +>f1 : (_i: number, ...restParameters: any[]) => void +>_i : number +>restParameters : any[] + + var _i = 10; // no error +>_i : number +} +function f1NoError(_i: number) { // no error +>f1NoError : (_i: number) => void +>_i : number + + var _i = 10; // no error +>_i : number +} + +declare function f2(_i: number, ...restParameters); // no error - no code gen +>f2 : (_i: number, ...restParameters: any[]) => any +>_i : number +>restParameters : any[] + +declare function f2NoError(_i: number); // no error +>f2NoError : (_i: number) => any +>_i : number + +function f3(...restParameters) { +>f3 : (...restParameters: any[]) => void +>restParameters : any[] + + var _i = 10; // no error +>_i : number +} +function f3NoError() { +>f3NoError : () => void + + var _i = 10; // no error +>_i : number +} + +function f4(_i: number, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : number +>rest : any[] + +function f4(_i: string, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : string +>rest : any[] + +function f4(_i: any, ...rest) { // error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : any +>rest : any[] +} + +function f4NoError(_i: number); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : number + +function f4NoError(_i: string); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : string + +function f4NoError(_i: any) { // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : any +} + +declare function f5(_i: number, ...rest); // no codegen no error +>f5 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : number +>rest : any[] + +declare function f5(_i: string, ...rest); // no codegen no error +>f5 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : string +>rest : any[] + +declare function f6(_i: number); // no codegen no error +>f6 : { (_i: number): any; (_i: string): any; } +>_i : number + +declare function f6(_i: string); // no codegen no error +>f6 : { (_i: number): any; (_i: string): any; } +>_i : string + diff --git a/tests/baselines/reference/collisionRestParameterFunctionExpressions.errors.txt b/tests/baselines/reference/collisionRestParameterFunctionExpressions.errors.txt deleted file mode 100644 index c2c237f98b..0000000000 --- a/tests/baselines/reference/collisionRestParameterFunctionExpressions.errors.txt +++ /dev/null @@ -1,33 +0,0 @@ -tests/cases/compiler/collisionRestParameterFunctionExpressions.ts(2,17): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. -tests/cases/compiler/collisionRestParameterFunctionExpressions.ts(17,17): error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - - -==== tests/cases/compiler/collisionRestParameterFunctionExpressions.ts (2 errors) ==== - function foo() { - function f1(_i: number, ...restParameters) { //_i is error - ~~~~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - var _i = 10; // no error - } - function f1NoError(_i: number) { // no error - var _i = 10; // no error - } - function f3(...restParameters) { - var _i = 10; // no error - } - function f3NoError() { - var _i = 10; // no error - } - - function f4(_i: number, ...rest); // no codegen no error - function f4(_i: string, ...rest); // no codegen no error - function f4(_i: any, ...rest) { // error - ~~~~~~~ -!!! error TS2397: Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter. - } - - function f4NoError(_i: number); // no error - function f4NoError(_i: string); // no error - function f4NoError(_i: any) { // no error - } - } \ No newline at end of file diff --git a/tests/baselines/reference/collisionRestParameterFunctionExpressions.js b/tests/baselines/reference/collisionRestParameterFunctionExpressions.js index 4f1dea2b11..22709b087e 100644 --- a/tests/baselines/reference/collisionRestParameterFunctionExpressions.js +++ b/tests/baselines/reference/collisionRestParameterFunctionExpressions.js @@ -28,8 +28,8 @@ function foo() { function foo() { function f1(_i) { var restParameters = []; - for (var _i = 1; _i < arguments.length; _i++) { - restParameters[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + restParameters[_a - 1] = arguments[_a]; } var _i = 10; // no error } @@ -38,8 +38,8 @@ function foo() { } function f3() { var restParameters = []; - for (var _i = 0; _i < arguments.length; _i++) { - restParameters[_i - 0] = arguments[_i]; + for (var _a = 0; _a < arguments.length; _a++) { + restParameters[_a - 0] = arguments[_a]; } var _i = 10; // no error } @@ -48,8 +48,8 @@ function foo() { } function f4(_i) { var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + for (var _a = 1; _a < arguments.length; _a++) { + rest[_a - 1] = arguments[_a]; } } function f4NoError(_i) { diff --git a/tests/baselines/reference/collisionRestParameterFunctionExpressions.types b/tests/baselines/reference/collisionRestParameterFunctionExpressions.types new file mode 100644 index 0000000000..c6c5239089 --- /dev/null +++ b/tests/baselines/reference/collisionRestParameterFunctionExpressions.types @@ -0,0 +1,62 @@ +=== tests/cases/compiler/collisionRestParameterFunctionExpressions.ts === +function foo() { +>foo : () => void + + function f1(_i: number, ...restParameters) { //_i is error +>f1 : (_i: number, ...restParameters: any[]) => void +>_i : number +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } + function f1NoError(_i: number) { // no error +>f1NoError : (_i: number) => void +>_i : number + + var _i = 10; // no error +>_i : number + } + function f3(...restParameters) { +>f3 : (...restParameters: any[]) => void +>restParameters : any[] + + var _i = 10; // no error +>_i : number + } + function f3NoError() { +>f3NoError : () => void + + var _i = 10; // no error +>_i : number + } + + function f4(_i: number, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : number +>rest : any[] + + function f4(_i: string, ...rest); // no codegen no error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : string +>rest : any[] + + function f4(_i: any, ...rest) { // error +>f4 : { (_i: number, ...rest: any[]): any; (_i: string, ...rest: any[]): any; } +>_i : any +>rest : any[] + } + + function f4NoError(_i: number); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : number + + function f4NoError(_i: string); // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : string + + function f4NoError(_i: any) { // no error +>f4NoError : { (_i: number): any; (_i: string): any; } +>_i : any + } +} diff --git a/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.errors.txt b/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.errors.txt deleted file mode 100644 index 08df732096..0000000000 --- a/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.errors.txt +++ /dev/null @@ -1,14 +0,0 @@ -tests/cases/compiler/collisionRestParameterUnderscoreIUsage.ts(5,21): error TS2398: Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter. - - -==== tests/cases/compiler/collisionRestParameterUnderscoreIUsage.ts (1 errors) ==== - declare var console: { log(msg?: string): void; }; - var _i = "This is what I'd expect to see"; - class Foo { - constructor(...args: any[]) { - console.log(_i); // This should result in error - ~~ -!!! error TS2398: Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter. - } - } - new Foo(); \ No newline at end of file diff --git a/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.js b/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.js index b8d3aaec91..adc9c09de2 100644 --- a/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.js +++ b/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.js @@ -13,8 +13,8 @@ var _i = "This is what I'd expect to see"; var Foo = (function () { function Foo() { var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; + for (var _a = 0; _a < arguments.length; _a++) { + args[_a - 0] = arguments[_a]; } console.log(_i); // This should result in error } diff --git a/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.types b/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.types new file mode 100644 index 0000000000..c700f50aca --- /dev/null +++ b/tests/baselines/reference/collisionRestParameterUnderscoreIUsage.types @@ -0,0 +1,27 @@ +=== tests/cases/compiler/collisionRestParameterUnderscoreIUsage.ts === +declare var console: { log(msg?: string): void; }; +>console : { log(msg?: string): void; } +>log : (msg?: string) => void +>msg : string + +var _i = "This is what I'd expect to see"; +>_i : string + +class Foo { +>Foo : Foo + + constructor(...args: any[]) { +>args : any[] + + console.log(_i); // This should result in error +>console.log(_i) : void +>console.log : (msg?: string) => void +>console : { log(msg?: string): void; } +>log : (msg?: string) => void +>_i : string + } +} +new Foo(); +>new Foo() : Foo +>Foo : typeof Foo + diff --git a/tests/baselines/reference/declarationInAmbientContext.errors.txt b/tests/baselines/reference/declarationInAmbientContext.errors.txt new file mode 100644 index 0000000000..338da990a0 --- /dev/null +++ b/tests/baselines/reference/declarationInAmbientContext.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/es6/destructuring/declarationInAmbientContext.ts(1,13): error TS1183: Destructuring declarations are not allowed in ambient contexts. +tests/cases/conformance/es6/destructuring/declarationInAmbientContext.ts(2,13): error TS1183: Destructuring declarations are not allowed in ambient contexts. + + +==== tests/cases/conformance/es6/destructuring/declarationInAmbientContext.ts (2 errors) ==== + declare var [a, b]; // Error, destructuring declaration not allowed in ambient context + ~~~~~~ +!!! error TS1183: Destructuring declarations are not allowed in ambient contexts. + declare var {c, d}; // Error, destructuring declaration not allowed in ambient context + ~~~~~~ +!!! error TS1183: Destructuring declarations are not allowed in ambient contexts. + \ No newline at end of file diff --git a/tests/baselines/reference/declarationWithNoInitializer.errors.txt b/tests/baselines/reference/declarationWithNoInitializer.errors.txt new file mode 100644 index 0000000000..226b3666ba --- /dev/null +++ b/tests/baselines/reference/declarationWithNoInitializer.errors.txt @@ -0,0 +1,12 @@ +tests/cases/conformance/es6/destructuring/declarationWithNoInitializer.ts(1,5): error TS1182: A destructuring declaration must have an initializer. +tests/cases/conformance/es6/destructuring/declarationWithNoInitializer.ts(2,5): error TS1182: A destructuring declaration must have an initializer. + + +==== tests/cases/conformance/es6/destructuring/declarationWithNoInitializer.ts (2 errors) ==== + var [a, b]; // Error, no initializer + ~~~~~~ +!!! error TS1182: A destructuring declaration must have an initializer. + var {c, d}; // Error, no initializer + ~~~~~~ +!!! error TS1182: A destructuring declaration must have an initializer. + \ No newline at end of file diff --git a/tests/baselines/reference/declarationsAndAssignments.errors.txt b/tests/baselines/reference/declarationsAndAssignments.errors.txt new file mode 100644 index 0000000000..2c9a54c869 --- /dev/null +++ b/tests/baselines/reference/declarationsAndAssignments.errors.txt @@ -0,0 +1,202 @@ +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(5,16): error TS2460: Type '[number, string]' has no property '2'. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(56,17): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(63,13): error TS2460: Type '[number]' has no property '1'. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(63,16): error TS2460: Type '[number]' has no property '2'. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(67,9): error TS2461: Type '{ [x: number]: undefined; }' is not an array type. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(68,9): error TS2461: Type '{ [x: number]: number; 0: number; 1: number; }' is not an array type. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(73,11): error TS2459: Type '{}' has no property 'a' and no string index signature. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(73,14): error TS2459: Type '{}' has no property 'b' and no string index signature. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(74,11): error TS2459: Type 'undefined[]' has no property 'a' and no string index signature. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(74,14): error TS2459: Type 'undefined[]' has no property 'b' and no string index signature. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(106,5): error TS2345: Argument of type '[number, [string, { y: boolean; }]]' is not assignable to parameter of type '[number, [string, { x: any; y?: boolean; }]]'. + Types of property '1' are incompatible. + Type '[string, { y: boolean; }]' is not assignable to type '[string, { x: any; y?: boolean; }]'. + Types of property '1' are incompatible. + Type '{ y: boolean; }' is not assignable to type '{ x: any; y?: boolean; }'. + Property 'x' is missing in type '{ y: boolean; }'. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,6): error TS2322: Type 'string' is not assignable to type 'number'. +tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,9): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts (13 errors) ==== + function f0() { + var [] = [1, "hello"]; + var [x] = [1, "hello"]; + var [x, y] = [1, "hello"]; + var [x, y, z] = [1, "hello"]; // Error + ~ +!!! error TS2460: Type '[number, string]' has no property '2'. + var [,, z] = [0, 1, 2]; + var x: number; + var y: string; + } + + function f1() { + var a = [1, "hello"]; + var [x] = a; + var [x, y] = a; + var [x, y, z] = a; + var x: number | string; + var y: number | string; + var z: number | string; + } + + function f2() { + var { } = { x: 5, y: "hello" }; + var { x } = { x: 5, y: "hello" }; + var { y } = { x: 5, y: "hello" }; + var { x, y } = { x: 5, y: "hello" }; + var x: number; + var y: string; + var { x: a } = { x: 5, y: "hello" }; + var { y: b } = { x: 5, y: "hello" }; + var { x: a, y: b } = { x: 5, y: "hello" }; + var a: number; + var b: string; + } + + function f3() { + var [x, [y, [z]]] = [1, ["hello", [true]]]; + var x: number; + var y: string; + var z: boolean; + } + + function f4() { + var { a: x, b: { a: y, b: { a: z }}} = { a: 1, b: { a: "hello", b: { a: true } } }; + var x: number; + var y: string; + var z: boolean; + } + + function f6() { + var [x = 0, y = ""] = [1, "hello"]; + var x: number; + var y: string; + } + + function f7() { + var [x = 0, y = 1] = [1, "hello"]; // Error, initializer for y must be string + ~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + var x: number; + var y: string; + } + + function f8() { + var [a, b, c] = []; // Ok, [] is an array + var [d, e, f] = [1]; // Error, [1] is a tuple + ~ +!!! error TS2460: Type '[number]' has no property '1'. + ~ +!!! error TS2460: Type '[number]' has no property '2'. + } + + function f9() { + var [a, b] = {}; // Error, not array type + ~~~~~~ +!!! error TS2461: Type '{ [x: number]: undefined; }' is not an array type. + var [c, d] = { 0: 10, 1: 20 }; // Error, not array type + ~~~~~~ +!!! error TS2461: Type '{ [x: number]: number; 0: number; 1: number; }' is not an array type. + var [e, f] = [10, 20]; + } + + function f10() { + var { a, b } = {}; // Error + ~ +!!! error TS2459: Type '{}' has no property 'a' and no string index signature. + ~ +!!! error TS2459: Type '{}' has no property 'b' and no string index signature. + var { a, b } = []; // Error + ~ +!!! error TS2459: Type 'undefined[]' has no property 'a' and no string index signature. + ~ +!!! error TS2459: Type 'undefined[]' has no property 'b' and no string index signature. + } + + function f11() { + var { x: a, y: b } = { x: 10, y: "hello" }; + var { 0: a, 1: b } = { 0: 10, 1: "hello" }; + var { "<": a, ">": b } = { "<": 10, ">": "hello" }; + var { 0: a, 1: b } = [10, "hello"]; + var a: number; + var b: string; + } + + function f12() { + var [a, [b, { x, y: c }] = ["abc", { x: 10, y: false }]] = [1, ["hello", { x: 5, y: true }]]; + var a: number; + var b: string; + var x: number; + var c: boolean; + } + + function f13() { + var [x, y] = [1, "hello"]; + var [a, b] = [[x, y], { x: x, y: y }]; + } + + function f14([a = 1, [b = "hello", { x, y: c = false }]]) { + var a: number; + var b: string; + var c: boolean; + } + f14([2, ["abc", { x: 0, y: true }]]); + f14([2, ["abc", { x: 0 }]]); + f14([2, ["abc", { y: false }]]); // Error, no x + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '[number, [string, { y: boolean; }]]' is not assignable to parameter of type '[number, [string, { x: any; y?: boolean; }]]'. +!!! error TS2345: Types of property '1' are incompatible. +!!! error TS2345: Type '[string, { y: boolean; }]' is not assignable to type '[string, { x: any; y?: boolean; }]'. +!!! error TS2345: Types of property '1' are incompatible. +!!! error TS2345: Type '{ y: boolean; }' is not assignable to type '{ x: any; y?: boolean; }'. +!!! error TS2345: Property 'x' is missing in type '{ y: boolean; }'. + + module M { + export var [a, b] = [1, 2]; + } + + function f15() { + var a = "hello"; + var b = 1; + var c = true; + return { a, b, c }; + } + + function f16() { + var { a, b, c } = f15(); + } + + function f17({ a = "", b = 0, c = false }) { + } + + f17({}); + f17({ a: "hello" }); + f17({ c: true }); + f17(f15()); + + function g4() { + var a: number; + var b: string; + var aa: number[]; + ({ a, b } = { a, b }); + ({ a, b } = { b, a }); + [aa[0], b] = [a, b]; + [a, b] = [b, a]; // Error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'number'. + ~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + [a = 1, b = "abc"] = [2, "def"]; + } + + function g5() { + var a, b; + [a, b] = [1, 2]; + [a, b] = [b, a]; + ({ a, b } = { b, a }); + [[a, b] = [1, 2]] = [[2, 3]]; + var x = ([a, b] = [1, 2]); + } + \ No newline at end of file diff --git a/tests/baselines/reference/declarationsAndAssignments.js b/tests/baselines/reference/declarationsAndAssignments.js new file mode 100644 index 0000000000..82272a5555 --- /dev/null +++ b/tests/baselines/reference/declarationsAndAssignments.js @@ -0,0 +1,288 @@ +//// [declarationsAndAssignments.ts] +function f0() { + var [] = [1, "hello"]; + var [x] = [1, "hello"]; + var [x, y] = [1, "hello"]; + var [x, y, z] = [1, "hello"]; // Error + var [,, z] = [0, 1, 2]; + var x: number; + var y: string; +} + +function f1() { + var a = [1, "hello"]; + var [x] = a; + var [x, y] = a; + var [x, y, z] = a; + var x: number | string; + var y: number | string; + var z: number | string; +} + +function f2() { + var { } = { x: 5, y: "hello" }; + var { x } = { x: 5, y: "hello" }; + var { y } = { x: 5, y: "hello" }; + var { x, y } = { x: 5, y: "hello" }; + var x: number; + var y: string; + var { x: a } = { x: 5, y: "hello" }; + var { y: b } = { x: 5, y: "hello" }; + var { x: a, y: b } = { x: 5, y: "hello" }; + var a: number; + var b: string; +} + +function f3() { + var [x, [y, [z]]] = [1, ["hello", [true]]]; + var x: number; + var y: string; + var z: boolean; +} + +function f4() { + var { a: x, b: { a: y, b: { a: z }}} = { a: 1, b: { a: "hello", b: { a: true } } }; + var x: number; + var y: string; + var z: boolean; +} + +function f6() { + var [x = 0, y = ""] = [1, "hello"]; + var x: number; + var y: string; +} + +function f7() { + var [x = 0, y = 1] = [1, "hello"]; // Error, initializer for y must be string + var x: number; + var y: string; +} + +function f8() { + var [a, b, c] = []; // Ok, [] is an array + var [d, e, f] = [1]; // Error, [1] is a tuple +} + +function f9() { + var [a, b] = {}; // Error, not array type + var [c, d] = { 0: 10, 1: 20 }; // Error, not array type + var [e, f] = [10, 20]; +} + +function f10() { + var { a, b } = {}; // Error + var { a, b } = []; // Error +} + +function f11() { + var { x: a, y: b } = { x: 10, y: "hello" }; + var { 0: a, 1: b } = { 0: 10, 1: "hello" }; + var { "<": a, ">": b } = { "<": 10, ">": "hello" }; + var { 0: a, 1: b } = [10, "hello"]; + var a: number; + var b: string; +} + +function f12() { + var [a, [b, { x, y: c }] = ["abc", { x: 10, y: false }]] = [1, ["hello", { x: 5, y: true }]]; + var a: number; + var b: string; + var x: number; + var c: boolean; +} + +function f13() { + var [x, y] = [1, "hello"]; + var [a, b] = [[x, y], { x: x, y: y }]; +} + +function f14([a = 1, [b = "hello", { x, y: c = false }]]) { + var a: number; + var b: string; + var c: boolean; +} +f14([2, ["abc", { x: 0, y: true }]]); +f14([2, ["abc", { x: 0 }]]); +f14([2, ["abc", { y: false }]]); // Error, no x + +module M { + export var [a, b] = [1, 2]; +} + +function f15() { + var a = "hello"; + var b = 1; + var c = true; + return { a, b, c }; +} + +function f16() { + var { a, b, c } = f15(); +} + +function f17({ a = "", b = 0, c = false }) { +} + +f17({}); +f17({ a: "hello" }); +f17({ c: true }); +f17(f15()); + +function g4() { + var a: number; + var b: string; + var aa: number[]; + ({ a, b } = { a, b }); + ({ a, b } = { b, a }); + [aa[0], b] = [a, b]; + [a, b] = [b, a]; // Error + [a = 1, b = "abc"] = [2, "def"]; +} + +function g5() { + var a, b; + [a, b] = [1, 2]; + [a, b] = [b, a]; + ({ a, b } = { b, a }); + [[a, b] = [1, 2]] = [[2, 3]]; + var x = ([a, b] = [1, 2]); +} + + +//// [declarationsAndAssignments.js] +function f0() { + var _a = [1, "hello"]; + var x = ([1, "hello"])[0]; + var _b = [1, "hello"], x = _b[0], y = _b[1]; + var _c = [1, "hello"], x = _c[0], y = _c[1], z = _c[2]; // Error + var _d = [0, 1, 2], z = _d[2]; + var x; + var y; +} +function f1() { + var a = [1, "hello"]; + var x = a[0]; + var x = a[0], y = a[1]; + var x = a[0], y = a[1], z = a[2]; + var x; + var y; + var z; +} +function f2() { + var _a = { x: 5, y: "hello" }; + var x = ({ x: 5, y: "hello" }).x; + var y = ({ x: 5, y: "hello" }).y; + var _b = { x: 5, y: "hello" }, x = _b.x, y = _b.y; + var x; + var y; + var a = ({ x: 5, y: "hello" }).x; + var b = ({ x: 5, y: "hello" }).y; + var _c = { x: 5, y: "hello" }, a = _c.x, b = _c.y; + var a; + var b; +} +function f3() { + var _a = [1, ["hello", [true]]], x = _a[0], _b = _a[1], y = _b[0], z = _b[1][0]; + var x; + var y; + var z; +} +function f4() { + var _a = { a: 1, b: { a: "hello", b: { a: true } } }, x = _a.a, _b = _a.b, y = _b.a, z = _b.b.a; + var x; + var y; + var z; +} +function f6() { + var _a = [1, "hello"], _b = _a[0], x = _b === void0 ? 0 : _b, _c = _a[1], y = _c === void0 ? "" : _c; + var x; + var y; +} +function f7() { + var _a = [1, "hello"], _b = _a[0], x = _b === void0 ? 0 : _b, _c = _a[1], y = _c === void0 ? 1 : _c; // Error, initializer for y must be string + var x; + var y; +} +function f8() { + var _a = [], a = _a[0], b = _a[1], c = _a[2]; // Ok, [] is an array + var _b = [1], d = _b[0], e = _b[1], f = _b[2]; // Error, [1] is a tuple +} +function f9() { + var _a = {}, a = _a[0], b = _a[1]; // Error, not array type + var _b = { 0: 10, 1: 20 }, c = _b[0], d = _b[1]; // Error, not array type + var _c = [10, 20], e = _c[0], f = _c[1]; +} +function f10() { + var _a = {}, a = _a.a, b = _a.b; // Error + var _b = [], a = _b.a, b = _b.b; // Error +} +function f11() { + var _a = { x: 10, y: "hello" }, a = _a.x, b = _a.y; + var _b = { 0: 10, 1: "hello" }, a = _b[0], b = _b[1]; + var _c = { "<": 10, ">": "hello" }, a = _c["<"], b = _c[">"]; + var _d = [10, "hello"], a = _d[0], b = _d[1]; + var a; + var b; +} +function f12() { + var _a = [1, ["hello", { x: 5, y: true }]], a = _a[0], _b = _a[1], _c = _b === void0 ? ["abc", { x: 10, y: false }] : _b, b = _c[0], _d = _c[1], x = _d.x, c = _d.y; + var a; + var b; + var x; + var c; +} +function f13() { + var _a = [1, "hello"], x = _a[0], y = _a[1]; + var _b = [[x, y], { x: x, y: y }], a = _b[0], b = _b[1]; +} +function f14(_a) { + var _b = _a[0], a = _b === void0 ? 1 : _b, _c = _a[1], _d = _c[0], b = _d === void0 ? "hello" : _d, _e = _c[1], x = _e.x, _f = _e.y, c = _f === void0 ? false : _f; + var a; + var b; + var c; +} +f14([2, ["abc", { x: 0, y: true }]]); +f14([2, ["abc", { x: 0 }]]); +f14([2, ["abc", { y: false }]]); // Error, no x +var M; +(function (M) { + _a = [1, 2], M.a = _a[0], M.b = _a[1]; + var _a; +})(M || (M = {})); +function f15() { + var a = "hello"; + var b = 1; + var c = true; + return { a: a, b: b, c: c }; +} +function f16() { + var _a = f15(), a = _a.a, b = _a.b, c = _a.c; +} +function f17(_a) { + var _b = _a.a, a = _b === void0 ? "" : _b, _c = _a.b, b = _c === void0 ? 0 : _c, _d = _a.c, c = _d === void0 ? false : _d; +} +f17({}); +f17({ a: "hello" }); +f17({ c: true }); +f17(f15()); +function g4() { + var a; + var b; + var aa; + (_a = { a: a, b: b }, a = _a.a, b = _a.b, _a); + (_b = { b: b, a: a }, a = _b.a, b = _b.b, _b); + _c = [a, b], aa[0] = _c[0], b = _c[1]; + _d = [b, a], a = _d[0], b = _d[1]; // Error + _e = [2, "def"], _f = _e[0], a = _f === void0 ? 1 : _f, _g = _e[1], b = _g === void0 ? "abc" : _g; + var _a, _b, _c, _d, _e, _f, _g; +} +function g5() { + var a, b; + _a = [1, 2], a = _a[0], b = _a[1]; + _b = [b, a], a = _b[0], b = _b[1]; + (_c = { b: b, a: a }, a = _c.a, b = _c.b, _c); + _d = ([[2, 3]])[0], _e = _d === void0 ? [1, 2] : _d, a = _e[0], b = _e[1]; + var x = (_f = [1, 2], a = _f[0], b = _f[1], _f); + var _a, _b, _c, _d, _e, _f; +} diff --git a/tests/baselines/reference/genericCallWithObjectTypeArgs2.types b/tests/baselines/reference/genericCallWithObjectTypeArgs2.types index 3e178a7062..08bce90b5d 100644 --- a/tests/baselines/reference/genericCallWithObjectTypeArgs2.types +++ b/tests/baselines/reference/genericCallWithObjectTypeArgs2.types @@ -56,7 +56,7 @@ var r = f({ x: new Derived(), y: new Derived2() }); // {}[] >Derived2 : typeof Derived2 var r2 = f({ x: new Base(), y: new Derived2() }); // {}[] ->r2 : Base[] +>r2 : (Base | Derived2)[] >f({ x: new Base(), y: new Derived2() }) : (Base | Derived2)[] >f : (a: { x: T; y: U; }) => (T | U)[] >{ x: new Base(), y: new Derived2() } : { x: Base; y: Derived2; } diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList1.errors.txt b/tests/baselines/reference/parserErrorRecovery_ParameterList1.errors.txt index 1e8f35de06..c2308f6fb1 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList1.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList1.errors.txt @@ -1,8 +1,14 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList1.ts(1,14): error TS1005: ')' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList1.ts(1,14): error TS1005: ',' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList1.ts(2,2): error TS1005: ')' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList1.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList1.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList1.ts (3 errors) ==== function f(a { ~ -!!! error TS1005: ')' expected. - } \ No newline at end of file +!!! error TS1005: ',' expected. + ~ +!!! error TS2391: Function implementation is missing or not immediately following the declaration. + } + +!!! error TS1005: ')' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList2.errors.txt b/tests/baselines/reference/parserErrorRecovery_ParameterList2.errors.txt index 48cd83147d..43e3f9f028 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList2.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList2.errors.txt @@ -1,8 +1,11 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList2.ts(1,15): error TS1005: ')' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList2.ts(2,2): error TS1005: ')' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList2.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList2.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList2.ts (2 errors) ==== function f(a, { - ~ -!!! error TS1005: ')' expected. - } \ No newline at end of file + ~ +!!! error TS2391: Function implementation is missing or not immediately following the declaration. + } + +!!! error TS1005: ')' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt b/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt index 1d3a9d901c..8d15f746d2 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList5.errors.txt @@ -1,10 +1,10 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList5.ts(1,11): error TS1005: ',' expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList5.ts(1,14): error TS1005: ')' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList5.ts(1,17): error TS1005: ')' expected. ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList5.ts (2 errors) ==== (a:number => { } ~~ !!! error TS1005: ',' expected. - ~ + !!! error TS1005: ')' expected. \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeEquivalence.errors.txt b/tests/baselines/reference/unionTypeEquivalence.errors.txt new file mode 100644 index 0000000000..d561a96f97 --- /dev/null +++ b/tests/baselines/reference/unionTypeEquivalence.errors.txt @@ -0,0 +1,25 @@ +tests/cases/conformance/types/union/unionTypeEquivalence.ts(5,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'C', but here has type 'C | D'. + + +==== tests/cases/conformance/types/union/unionTypeEquivalence.ts (1 errors) ==== + // A | B is equivalent to A if B is a subtype of A + class C { } + class D extends C { foo() { } } + var x: C; + var x : C | D; + ~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'C', but here has type 'C | D'. + + // A | B is equivalent to B | A. + var y: string | number; + var y : number | string; + + // AB | C is equivalent to A | BC, where AB is A | B and BC is B | C. + var z : string | number | boolean; + var z : (string | number) | boolean; + var z : string | (number | boolean); + var AB : string | number; + var BC : number | boolean; + var z1: typeof AB | boolean; + var z1: string | typeof BC; + \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeEquivalence.types b/tests/baselines/reference/unionTypeEquivalence.types deleted file mode 100644 index c4990a5813..0000000000 --- a/tests/baselines/reference/unionTypeEquivalence.types +++ /dev/null @@ -1,50 +0,0 @@ -=== tests/cases/conformance/types/union/unionTypeEquivalence.ts === -// A | B is equivalent to A if B is a subtype of A -class C { } ->C : C - -class D extends C { foo() { } } ->D : D ->C : C ->foo : () => void - -var x: C; ->x : C ->C : C - -var x : C | D; ->x : C ->C : C ->D : D - -// A | B is equivalent to B | A. -var y: string | number; ->y : string | number - -var y : number | string; ->y : string | number - -// AB | C is equivalent to A | BC, where AB is A | B and BC is B | C. -var z : string | number | boolean; ->z : string | number | boolean - -var z : (string | number) | boolean; ->z : string | number | boolean - -var z : string | (number | boolean); ->z : string | number | boolean - -var AB : string | number; ->AB : string | number - -var BC : number | boolean; ->BC : number | boolean - -var z1: typeof AB | boolean; ->z1 : string | number | boolean ->AB : string | number - -var z1: string | typeof BC; ->z1 : string | number | boolean ->BC : number | boolean - diff --git a/tests/baselines/reference/unionTypeLiterals.errors.txt b/tests/baselines/reference/unionTypeLiterals.errors.txt new file mode 100644 index 0000000000..d976d769f5 --- /dev/null +++ b/tests/baselines/reference/unionTypeLiterals.errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/types/specifyingTypes/typeLiterals/unionTypeLiterals.ts(11,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'unionOfFunctionType' must be of type '(() => string) | (() => number)', but here has type '() => string | number'. +tests/cases/conformance/types/specifyingTypes/typeLiterals/unionTypeLiterals.ts(15,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'unionOfConstructorType' must be of type '(new () => string) | (new () => number)', but here has type 'new () => string | number'. + + +==== tests/cases/conformance/types/specifyingTypes/typeLiterals/unionTypeLiterals.ts (2 errors) ==== + // basic valid forms of union literals + + var simpleUnion: string | number; + var unionOfUnion: string | number | boolean; + + var arrayOfUnions: (string | number)[]; + var arrayOfUnions: Array; + + var unionOfFunctionType: (() => string) | (() => number); + var unionOfFunctionType: { (): string } | { (): number }; + var unionOfFunctionType: () => string | number; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'unionOfFunctionType' must be of type '(() => string) | (() => number)', but here has type '() => string | number'. + + var unionOfConstructorType: (new () => string) | (new () => number); + var unionOfConstructorType: { new (): string } | { new (): number }; + var unionOfConstructorType: new () => string | number; + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'unionOfConstructorType' must be of type '(new () => string) | (new () => number)', but here has type 'new () => string | number'. \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeLiterals.types b/tests/baselines/reference/unionTypeLiterals.types deleted file mode 100644 index 90bc4649aa..0000000000 --- a/tests/baselines/reference/unionTypeLiterals.types +++ /dev/null @@ -1,34 +0,0 @@ -=== tests/cases/conformance/types/specifyingTypes/typeLiterals/unionTypeLiterals.ts === -// basic valid forms of union literals - -var simpleUnion: string | number; ->simpleUnion : string | number - -var unionOfUnion: string | number | boolean; ->unionOfUnion : string | number | boolean - -var arrayOfUnions: (string | number)[]; ->arrayOfUnions : (string | number)[] - -var arrayOfUnions: Array; ->arrayOfUnions : (string | number)[] ->Array : T[] - -var unionOfFunctionType: (() => string) | (() => number); ->unionOfFunctionType : (() => string) | (() => number) - -var unionOfFunctionType: { (): string } | { (): number }; ->unionOfFunctionType : (() => string) | (() => number) - -var unionOfFunctionType: () => string | number; ->unionOfFunctionType : (() => string) | (() => number) - -var unionOfConstructorType: (new () => string) | (new () => number); ->unionOfConstructorType : (new () => string) | (new () => number) - -var unionOfConstructorType: { new (): string } | { new (): number }; ->unionOfConstructorType : (new () => string) | (new () => number) - -var unionOfConstructorType: new () => string | number; ->unionOfConstructorType : (new () => string) | (new () => number) - diff --git a/tests/cases/conformance/es6/destructuring/declarationInAmbientContext.ts b/tests/cases/conformance/es6/destructuring/declarationInAmbientContext.ts new file mode 100644 index 0000000000..a3db3753de --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/declarationInAmbientContext.ts @@ -0,0 +1,2 @@ +declare var [a, b]; // Error, destructuring declaration not allowed in ambient context +declare var {c, d}; // Error, destructuring declaration not allowed in ambient context diff --git a/tests/cases/conformance/es6/destructuring/declarationWithNoInitializer.ts b/tests/cases/conformance/es6/destructuring/declarationWithNoInitializer.ts new file mode 100644 index 0000000000..1fb8b07e58 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/declarationWithNoInitializer.ts @@ -0,0 +1,2 @@ +var [a, b]; // Error, no initializer +var {c, d}; // Error, no initializer diff --git a/tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts b/tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts new file mode 100644 index 0000000000..04cdd153a5 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts @@ -0,0 +1,149 @@ +function f0() { + var [] = [1, "hello"]; + var [x] = [1, "hello"]; + var [x, y] = [1, "hello"]; + var [x, y, z] = [1, "hello"]; // Error + var [,, z] = [0, 1, 2]; + var x: number; + var y: string; +} + +function f1() { + var a = [1, "hello"]; + var [x] = a; + var [x, y] = a; + var [x, y, z] = a; + var x: number | string; + var y: number | string; + var z: number | string; +} + +function f2() { + var { } = { x: 5, y: "hello" }; + var { x } = { x: 5, y: "hello" }; + var { y } = { x: 5, y: "hello" }; + var { x, y } = { x: 5, y: "hello" }; + var x: number; + var y: string; + var { x: a } = { x: 5, y: "hello" }; + var { y: b } = { x: 5, y: "hello" }; + var { x: a, y: b } = { x: 5, y: "hello" }; + var a: number; + var b: string; +} + +function f3() { + var [x, [y, [z]]] = [1, ["hello", [true]]]; + var x: number; + var y: string; + var z: boolean; +} + +function f4() { + var { a: x, b: { a: y, b: { a: z }}} = { a: 1, b: { a: "hello", b: { a: true } } }; + var x: number; + var y: string; + var z: boolean; +} + +function f6() { + var [x = 0, y = ""] = [1, "hello"]; + var x: number; + var y: string; +} + +function f7() { + var [x = 0, y = 1] = [1, "hello"]; // Error, initializer for y must be string + var x: number; + var y: string; +} + +function f8() { + var [a, b, c] = []; // Ok, [] is an array + var [d, e, f] = [1]; // Error, [1] is a tuple +} + +function f9() { + var [a, b] = {}; // Error, not array type + var [c, d] = { 0: 10, 1: 20 }; // Error, not array type + var [e, f] = [10, 20]; +} + +function f10() { + var { a, b } = {}; // Error + var { a, b } = []; // Error +} + +function f11() { + var { x: a, y: b } = { x: 10, y: "hello" }; + var { 0: a, 1: b } = { 0: 10, 1: "hello" }; + var { "<": a, ">": b } = { "<": 10, ">": "hello" }; + var { 0: a, 1: b } = [10, "hello"]; + var a: number; + var b: string; +} + +function f12() { + var [a, [b, { x, y: c }] = ["abc", { x: 10, y: false }]] = [1, ["hello", { x: 5, y: true }]]; + var a: number; + var b: string; + var x: number; + var c: boolean; +} + +function f13() { + var [x, y] = [1, "hello"]; + var [a, b] = [[x, y], { x: x, y: y }]; +} + +function f14([a = 1, [b = "hello", { x, y: c = false }]]) { + var a: number; + var b: string; + var c: boolean; +} +f14([2, ["abc", { x: 0, y: true }]]); +f14([2, ["abc", { x: 0 }]]); +f14([2, ["abc", { y: false }]]); // Error, no x + +module M { + export var [a, b] = [1, 2]; +} + +function f15() { + var a = "hello"; + var b = 1; + var c = true; + return { a, b, c }; +} + +function f16() { + var { a, b, c } = f15(); +} + +function f17({ a = "", b = 0, c = false }) { +} + +f17({}); +f17({ a: "hello" }); +f17({ c: true }); +f17(f15()); + +function g4() { + var a: number; + var b: string; + var aa: number[]; + ({ a, b } = { a, b }); + ({ a, b } = { b, a }); + [aa[0], b] = [a, b]; + [a, b] = [b, a]; // Error + [a = 1, b = "abc"] = [2, "def"]; +} + +function g5() { + var a, b; + [a, b] = [1, 2]; + [a, b] = [b, a]; + ({ a, b } = { b, a }); + [[a, b] = [1, 2]] = [[2, 3]]; + var x = ([a, b] = [1, 2]); +} diff --git a/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts b/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts index 6536bb76e7..960a6b7a86 100644 --- a/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts +++ b/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts @@ -18,8 +18,8 @@ goTo.marker("propertyReference"); goTo.definition(0); -verify.caretAtMarker("propertyDefinition1"); +verify.caretAtMarker("propertyDefinition2"); goTo.marker("propertyReference"); goTo.definition(1); -verify.caretAtMarker("propertyDefinition2"); +verify.caretAtMarker("propertyDefinition1"); diff --git a/tests/cases/fourslash/unclosedFunctionErrorRecovery2.ts b/tests/cases/fourslash/unclosedFunctionErrorRecovery2.ts deleted file mode 100644 index 8af1be00cc..0000000000 --- a/tests/cases/fourslash/unclosedFunctionErrorRecovery2.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -////function alpha( {} -/////**/ -////function beta() { alpha(); } -//// - -verify.not.errorExistsAfterMarker(); \ No newline at end of file