From a3ffe6f874cdd7686013202f76962c8c7d8d74af Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 09:30:15 -0700 Subject: [PATCH 01/85] Parse, bind and check spread types and elements --- src/compiler/binder.ts | 12 +- src/compiler/checker.ts | 407 ++++++++++++++++++++++----- src/compiler/diagnosticMessages.json | 12 + src/compiler/parser.ts | 29 +- src/compiler/types.ts | 92 +++--- src/compiler/utilities.ts | 1 + src/harness/harness.ts | 2 +- src/services/findAllReferences.ts | 6 +- 8 files changed, 447 insertions(+), 114 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 49434e80abab4..d3217fd70a850 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1825,8 +1825,9 @@ namespace ts { case SyntaxKind.EnumMember: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes); + case SyntaxKind.SpreadElement: case SyntaxKind.JsxSpreadAttribute: - emitFlags |= NodeFlags.HasJsxSpreadAttributes; + emitFlags |= NodeFlags.HasSpreadAttribute; return; case SyntaxKind.CallSignature: @@ -2956,8 +2957,9 @@ namespace ts { } break; + case SyntaxKind.SpreadElement: case SyntaxKind.SpreadElementExpression: - // This node is ES6 syntax, but is handled by a containing node. + // This node is ES6 or ES future syntax, but is handled by a containing node. transformFlags |= TransformFlags.ContainsSpreadElementExpression; break; @@ -2996,6 +2998,12 @@ namespace ts { transformFlags |= TransformFlags.ContainsLexicalThis; } + if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) { + // If an ObjectLiteralExpression contains a spread element, then it + // is an ES experimental node. + transformFlags |= TransformFlags.AssertExperimental; + } + break; case SyntaxKind.ArrayLiteralExpression: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 51550ef873fc5..3578aeb5e4bb9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -112,6 +112,7 @@ namespace ts { const tupleTypes: GenericType[] = []; const unionTypes = createMap(); const intersectionTypes = createMap(); + const spreadTypes = createMap(); const stringLiteralTypes = createMap(); const numericLiteralTypes = createMap(); @@ -2185,7 +2186,10 @@ namespace ts { writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); } else if (type.flags & TypeFlags.UnionOrIntersection) { - writeUnionOrIntersectionType(type, nextFlags); + writeUnionOrIntersectionType(type, nextFlags); + } + else if (type.flags & TypeFlags.Spread) { + writeSpreadType(type, nextFlags); } else if (type.flags & TypeFlags.Anonymous) { writeAnonymousType(type, nextFlags); @@ -2279,7 +2283,7 @@ namespace ts { } } - function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) { + function writeUnionOrIntersectionType(type: TypeOperatorType, flags: TypeFormatFlags) { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } @@ -2294,6 +2298,36 @@ namespace ts { } } + function writeSpreadType(type: SpreadType, flags: TypeFormatFlags) { + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writer.writeLine(); + writer.increaseIndent(); + let printFollowingPunctuation = false; + for (const t of type.types) { + if (printFollowingPunctuation) { + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); + } + if (t.isDeclaredProperty) { + const saveInObjectTypeLiteral = inObjectTypeLiteral; + inObjectTypeLiteral = true; + writeObjectLiteralType(resolveStructuredTypeMembers(t)); + printFollowingPunctuation = false; + inObjectTypeLiteral = saveInObjectTypeLiteral; + } + else { + writePunctuation(writer, SyntaxKind.DotDotDotToken); + writeType(t, TypeFormatFlags.None); + printFollowingPunctuation = true; + } + } + writer.decreaseIndent(); + if (printFollowingPunctuation) { + writeSpace(writer); + } + writePunctuation(writer, SyntaxKind.CloseBraceToken); + } + function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) { const symbol = type.symbol; if (symbol) { @@ -2436,6 +2470,13 @@ namespace ts { writePunctuation(writer, SyntaxKind.OpenBraceToken); writer.writeLine(); writer.increaseIndent(); + writeObjectLiteralType(resolved); + writer.decreaseIndent(); + writePunctuation(writer, SyntaxKind.CloseBraceToken); + inObjectTypeLiteral = saveInObjectTypeLiteral; + } + + function writeObjectLiteralType(resolved: ResolvedType) { for (const signature of resolved.callSignatures) { buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack); writePunctuation(writer, SyntaxKind.SemicolonToken); @@ -2468,11 +2509,8 @@ namespace ts { writer.writeLine(); } } - writer.decreaseIndent(); - writePunctuation(writer, SyntaxKind.CloseBraceToken); - inObjectTypeLiteral = saveInObjectTypeLiteral; } - } + } function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) { const targetSymbol = getTargetSymbol(symbol); @@ -2981,7 +3019,11 @@ namespace ts { // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). const elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false); - if (!declaration.dotDotDotToken) { + if (declaration.dotDotDotToken) { + // Rest element has an array type with the same element type as the parent type + type = createArrayType(elementType); + } + else { // Use specific property type when parent is a tuple or numeric index type when parent is an array const propName = "" + indexOf(pattern.elements, declaration); type = isTupleLikeType(parentType) @@ -2997,10 +3039,6 @@ namespace ts { return unknownType; } } - else { - // Rest element has an array type with the same element type as the parent type - type = createArrayType(elementType); - } } // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. @@ -4266,6 +4304,22 @@ namespace ts { setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); } + function resolveSpreadTypeMembers(type: SpreadType) { + // The members and properties collections are empty for spread types. To get all properties of an + // spread type use getPropertiesOfType (only the language service uses this). + let stringIndexInfo: IndexInfo = undefined; + let numberIndexInfo: IndexInfo = undefined; + for (let i = type.types.length - 1; i > -1; i--) { + const t = type.types[i]; + stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); + numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); + if (!t.symbol || !(t.symbol.flags & SymbolFlags.Optional)) { + break; + } + } + setObjectTypeMembers(type, emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + } + function resolveAnonymousTypeMembers(type: AnonymousType) { const symbol = type.symbol; if (type.target) { @@ -4332,6 +4386,9 @@ namespace ts { else if (type.flags & TypeFlags.Intersection) { resolveIntersectionTypeMembers(type); } + else if (type.flags & TypeFlags.Spread) { + resolveSpreadTypeMembers(type); + } } return type; } @@ -4341,6 +4398,9 @@ namespace ts { if (type.flags & TypeFlags.ObjectType) { return resolveStructuredTypeMembers(type).properties; } + if (type.flags & TypeFlags.Spread) { + return getPropertiesOfType(type); + } return emptyArray; } @@ -4356,10 +4416,11 @@ namespace ts { } } - function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] { + function getPropertiesOfUnionOrIntersectionOrSpreadType(type: TypeOperatorType): Symbol[] { + const getProperty = type.flags & TypeFlags.Spread ? getPropertyOfSpreadType : getPropertyOfUnionOrIntersectionType; for (const current of type.types) { for (const prop of getPropertiesOfType(current)) { - getPropertyOfUnionOrIntersectionType(type, prop.name); + getProperty(type, prop.name); } // The properties of a union type are those that are present in all constituent types, so // we only need to check the properties of the first type @@ -4372,7 +4433,8 @@ namespace ts { function getPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); - return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(type) : getPropertiesOfObjectType(type); + return type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.Spread) ? getPropertiesOfUnionOrIntersectionOrSpreadType(type) : + getPropertiesOfObjectType(type); } /** @@ -4398,7 +4460,7 @@ namespace ts { function getApparentType(type: Type): Type { if (type.flags & TypeFlags.TypeParameter) { type = getApparentTypeOfTypeParameter(type); - } + } if (type.flags & TypeFlags.StringLike) { type = globalStringType; } @@ -4414,34 +4476,43 @@ namespace ts { return type; } - function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol { + function createUnionOrIntersectionProperty(containingType: TypeOperatorType, name: string): Symbol { const types = containingType.types; - let props: Symbol[]; - // Flags we want to propagate to the result if they exist in all source symbols - let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None; - let isReadonly = false; - for (const current of types) { - const type = getApparentType(current); - if (type !== unknownType) { - const prop = getPropertyOfType(type, name); - if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) { - commonFlags &= prop.flags; - if (!props) { - props = [prop]; - } - else if (!contains(props, prop)) { - props.push(prop); + return createUnionOrIntersectionOrSpreadPropertySymbol(containingType, name, () => { + let props: Symbol[]; + // Flags we want to propagate to the result if they exist in all source symbols + let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None; + let isReadonly = false; + for (const current of types) { + const type = getApparentType(current); + if (type !== unknownType) { + const prop = getPropertyOfType(type, name); + if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) { + commonFlags &= prop.flags; + if (!props) { + props = [prop]; + } + else if (!contains(props, prop)) { + props.push(prop); + } + if (isReadonlySymbol(prop)) { + isReadonly = true; + } } - if (isReadonlySymbol(prop)) { - isReadonly = true; + else if (containingType.flags & TypeFlags.Union) { + // A union type requires the property to be present in all constituent types + return [undefined, false, 0]; } } - else if (containingType.flags & TypeFlags.Union) { - // A union type requires the property to be present in all constituent types - return undefined; - } } - } + return [props, isReadonly, commonFlags]; + }); + } + + function createUnionOrIntersectionOrSpreadPropertySymbol(containingType: TypeOperatorType, + name: string, + symbolCreator: () => [Symbol[], boolean, SymbolFlags]) { + const [props, isReadonly, flags] = symbolCreator(); if (!props) { return undefined; } @@ -4469,17 +4540,17 @@ namespace ts { SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | - commonFlags, + flags, name); result.containingType = containingType; result.hasCommonType = hasCommonType; result.declarations = declarations; result.isReadonly = isReadonly; - result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes); + result.type = containingType.flags & TypeFlags.Intersection ? getIntersectionType(propTypes) : getUnionType(propTypes); return result; } - function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol { + function getPropertyOfUnionOrIntersectionType(type: TypeOperatorType, name: string): Symbol { const properties = type.resolvedProperties || (type.resolvedProperties = createMap()); let property = properties[name]; if (!property) { @@ -4491,6 +4562,61 @@ namespace ts { return property; } + function createSpreadProperty(containingType: SpreadType, name: string): Symbol { + const types = containingType.types; + return createUnionOrIntersectionOrSpreadPropertySymbol(containingType, name, () => { + let props: Symbol[]; + // Result is readonly if any source is readonly + let isReadonly = false; + // Result is optional if all sources are optional + let commonFlags = SymbolFlags.Optional; + for (let i = types.length - 1; i > -1; i--) { + const type = getApparentType(types[i]); + if (type !== unknownType) { + const prop = getPropertyOfType(type, name); + if (prop) { + if (prop.flags & SymbolFlags.Method && !types[i].isDeclaredProperty || + prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor)) { + // skip non-object-literal methods and set-only properties and keep looking + continue; + } + if (!props) { + props = [prop]; + } + else if (!contains(props, prop)) { + props.unshift(prop); + } + if (isReadonlySymbol(prop)) { + isReadonly = true; + } + if (getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) { + // return immediately because even if prop is optional, it would make the unioned spread property private + return [undefined, false, 0]; + } + if (!(prop.flags & SymbolFlags.Optional)) { + // Reset extraFlags to None since we found a non-optional property + commonFlags = SymbolFlags.None; + break; + } + } + } + } + return [props, isReadonly, commonFlags]; + }); + } + + function getPropertyOfSpreadType(type: TypeOperatorType, name: string): Symbol { + const properties = type.resolvedProperties || (type.resolvedProperties = createMap()); + let property = properties[name]; + if (!property) { + property = createSpreadProperty(type as SpreadType, name); + if (property) { + properties[name] = property; + } + } + return property; + } + /** * Return the symbol for the property with the given name in the given type. Creates synthetic union properties when * necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from @@ -4516,7 +4642,10 @@ namespace ts { return getPropertyOfObjectType(globalObjectType, name); } if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertyOfUnionOrIntersectionType(type, name); + return getPropertyOfUnionOrIntersectionType(type, name); + } + if (type.flags & TypeFlags.Spread) { + return getPropertyOfSpreadType(type, name); } return undefined; } @@ -5538,8 +5667,44 @@ namespace ts { function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - // Deferred resolution of members is handled by resolveObjectTypeMembers - const type = createObjectType(TypeFlags.Anonymous, node.symbol); + const isSpread = (node.kind === SyntaxKind.TypeLiteral && + find((node as TypeLiteralNode).members, elt => elt.kind === SyntaxKind.SpreadTypeElement)); + let type: ObjectType; + if (isSpread) { + let members: Map; + const spreads: SpreadElementType[] = []; + for (const member of (node as TypeLiteralNode).members) { + if (member.kind === SyntaxKind.SpreadTypeElement) { + if (members) { + const t = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined) as SpreadElementType; + t.isDeclaredProperty = true; + spreads.push(t); + members = undefined; + } + spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type) as SpreadElementType); + } + else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) { + // note that spread types don't include call and construct signatures + const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); + const text = getTextOfPropertyName(member.name); + const symbol = createSymbol(flags, text); + symbol.type = getTypeFromTypeNodeNoAlias((member as IndexSignatureDeclaration | PropertySignature | MethodSignature).type); + if (!members) { + members = createMap(); + } + members[symbol.name] = symbol; + } + } + if (members) { + const t = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined) as SpreadElementType; + t.isDeclaredProperty = true; + spreads.push(t); + } + return getSpreadType(spreads, node.symbol); + } + else { + type = createObjectType(TypeFlags.Anonymous, node.symbol); + } type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; links.resolvedType = type; @@ -5547,6 +5712,18 @@ namespace ts { return links.resolvedType; } + function getSpreadType(types: SpreadElementType[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + const id = getTypeListId(types); + if (id in spreadTypes) { + return spreadTypes[id]; + } + const spread = spreadTypes[id] = createObjectType(TypeFlags.Spread, symbol) as SpreadType; + spread.types = filter(types, t => !(t.flags & (TypeFlags.Null | TypeFlags.Undefined))); + spread.aliasSymbol = aliasSymbol; + spread.aliasTypeArguments = aliasTypeArguments; + return spread; + } + function createLiteralType(flags: TypeFlags, text: string) { const type = createType(flags); type.text = text; @@ -5937,6 +6114,9 @@ namespace ts { if (type.flags & TypeFlags.Intersection) { return getIntersectionType(instantiateList((type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes); } + if (type.flags & TypeFlags.Spread) { + return getSpreadType(instantiateList((type as SpreadType).types, mapper, instantiateType) as SpreadElementType[], type.symbol, type.aliasSymbol, mapper.targetTypes); + } } return type; } @@ -6460,6 +6640,26 @@ namespace ts { } } + if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { + const sourceParameters = filter((source as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); + const targetParameters = filter((target as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); + if (sourceParameters.length !== targetParameters.length) { + reportRelationError(headMessage, source, target); + return Ternary.False; + } + for (let i = 0; i < sourceParameters.length; i++) { + if (sourceParameters[i].symbol !== targetParameters[i].symbol) { + reportRelationError(headMessage, source, target); + return Ternary.False; + } + } + const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; + if (result = objectTypeRelatedTo(source, source, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + if (source.flags & TypeFlags.TypeParameter) { let constraint = getConstraintOfTypeParameter(source); @@ -6490,7 +6690,7 @@ namespace ts { // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates // to X. Failing both of those we want to check if the aggregation of A and B's members structurally // relates to X. Thus, we include intersection types on the source side here. - if (apparentSource.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) { + if (apparentSource.flags & (TypeFlags.ObjectType | TypeFlags.Intersection | TypeFlags.Spread) && target.flags & TypeFlags.ObjectType) { // Report structural errors only if we haven't reported any errors yet const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !(source.flags & TypeFlags.Primitive); if (result = objectTypeRelatedTo(apparentSource, source, target, reportStructuralErrors)) { @@ -6525,8 +6725,8 @@ namespace ts { } if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union || source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) { - if (result = eachTypeRelatedToSomeType(source, target, /*reportErrors*/ false)) { - if (result &= eachTypeRelatedToSomeType(target, source, /*reportErrors*/ false)) { + if (result = eachTypeRelatedToSomeType(source, target, /*reportErrors*/ false)) { + if (result &= eachTypeRelatedToSomeType(target, source, /*reportErrors*/ false)) { return result; } } @@ -6549,7 +6749,7 @@ namespace ts { } } else if (type.flags & TypeFlags.UnionOrIntersection) { - for (const t of (type).types) { + for (const t of (type).types) { if (isKnownProperty(t, name)) { return true; } @@ -6586,7 +6786,7 @@ namespace ts { return false; } - function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { + function eachTypeRelatedToSomeType(source: TypeOperatorType, target: TypeOperatorType, reportErrors: boolean): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { @@ -6599,7 +6799,7 @@ namespace ts { return result; } - function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { + function typeRelatedToSomeType(source: Type, target: TypeOperatorType, reportErrors: boolean): Ternary { const targetTypes = target.types; if (target.flags & TypeFlags.Union && containsType(targetTypes, source)) { return Ternary.True; @@ -6614,7 +6814,7 @@ namespace ts { return Ternary.False; } - function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { + function typeRelatedToEachType(source: Type, target: TypeOperatorType, reportErrors: boolean): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { @@ -6627,7 +6827,7 @@ namespace ts { return result; } - function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { + function someTypeRelatedToType(source: TypeOperatorType, target: Type, reportErrors: boolean): Ternary { const sourceTypes = source.types; if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { return Ternary.True; @@ -6642,7 +6842,7 @@ namespace ts { return Ternary.False; } - function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { + function eachTypeRelatedToType(source: TypeOperatorType, target: Type, reportErrors: boolean): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { @@ -7578,10 +7778,10 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter || type.flags & TypeFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || - type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); + type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); } - function couldUnionOrIntersectionContainTypeParameters(type: UnionOrIntersectionType): boolean { + function couldUnionOrIntersectionContainTypeParameters(type: TypeOperatorType): boolean { if (type.couldContainTypeParameters === undefined) { type.couldContainTypeParameters = forEach(type.types, couldContainTypeParameters); } @@ -7589,7 +7789,7 @@ namespace ts { } function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { - return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((type).types, t => isTypeParameterAtTopLevel(t, typeParameter)); + return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((type).types, t => isTypeParameterAtTopLevel(t, typeParameter)); } function inferTypes(context: InferenceContext, originalSource: Type, originalTarget: Type) { @@ -7619,7 +7819,7 @@ namespace ts { // Source and target are both unions or both intersections. If source and target // are the same type, just relate each constituent type to itself. if (source === target) { - for (const t of (source).types) { + for (const t of (source).types) { inferFromTypes(t, t); } return; @@ -7631,14 +7831,14 @@ namespace ts { // and string literals because the number and string types are not represented as unions // of all their possible values. let matchingTypes: Type[]; - for (const t of (source).types) { - if (typeIdenticalToSomeType(t, (target).types)) { + for (const t of (source).types) { + if (typeIdenticalToSomeType(t, (target).types)) { (matchingTypes || (matchingTypes = [])).push(t); inferFromTypes(t, t); } else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) { const b = getBaseTypeOfLiteralType(t); - if (typeIdenticalToSomeType(b, (target).types)) { + if (typeIdenticalToSomeType(b, (target).types)) { (matchingTypes || (matchingTypes = [])).push(t, b); } } @@ -7647,8 +7847,8 @@ namespace ts { // removing the identically matched constituents. For example, when inferring from // 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'. if (matchingTypes) { - source = removeTypesFromUnionOrIntersection(source, matchingTypes); - target = removeTypesFromUnionOrIntersection(target, matchingTypes); + source = removeTypesFromUnionOrIntersection(source, matchingTypes); + target = removeTypesFromUnionOrIntersection(target, matchingTypes); } } if (target.flags & TypeFlags.TypeParameter) { @@ -7695,7 +7895,7 @@ namespace ts { } } else if (target.flags & TypeFlags.UnionOrIntersection) { - const targetTypes = (target).types; + const targetTypes = (target).types; let typeParameterCount = 0; let typeParameter: TypeParameter; // First infer to each type in union or intersection that isn't a type parameter @@ -7719,7 +7919,7 @@ namespace ts { } else if (source.flags & TypeFlags.UnionOrIntersection) { // Source is a union or intersection type, infer from each constituent type - const sourceTypes = (source).types; + const sourceTypes = (source).types; for (const sourceType of sourceTypes) { inferFromTypes(sourceType, target); } @@ -7824,7 +8024,7 @@ namespace ts { * Return a new union or intersection type computed by removing a given set of types * from a given union or intersection type. */ - function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) { + function removeTypesFromUnionOrIntersection(type: TypeOperatorType, typesToRemove: Type[]) { const reducedTypes: Type[] = []; for (const t of type.types) { if (!typeIdenticalToSomeType(t, typesToRemove)) { @@ -8148,7 +8348,7 @@ namespace ts { return getTypeFacts(constraint || emptyObjectType); } if (flags & TypeFlags.UnionOrIntersection) { - return getTypeFactsOfTypes((type).types); + return getTypeFactsOfTypes((type).types); } return TypeFacts.All; } @@ -10184,8 +10384,9 @@ namespace ts { // Grammar checking checkGrammarObjectLiteralExpression(node, inDestructuringPattern); - const propertiesTable = createMap(); - const propertiesArray: Symbol[] = []; + let propertiesTable = createMap(); + let propertiesArray: Symbol[] = []; + const spreads: SpreadElementType[] = []; const contextualType = getApparentTypeOfContextualType(node); const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); @@ -10210,6 +10411,14 @@ namespace ts { Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment); type = checkExpressionForMutableLocation((memberDecl).name, contextualMapper); } + + if (hasProperty(propertiesTable, member.name)) { + const existingPropType = getTypeOfSymbol(propertiesTable[member.name]); + if (!isTypeIdenticalTo(existingPropType, type)) { + error(memberDecl.name, Diagnostics.Cannot_change_type_of_property_0_from_1_to_2, member.name, typeToString(existingPropType), typeToString(type)); + } + } + typeFlags |= type.flags; const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name); if (inDestructuringPattern) { @@ -10247,6 +10456,19 @@ namespace ts { prop.target = member; member = prop; } + else if (memberDecl.kind === SyntaxKind.SpreadElement) { + if (propertiesArray.length > 0) { + const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType; + t.isDeclaredProperty = true; + spreads.push(t); + propertiesArray = []; + propertiesTable = createMap(); + hasComputedStringProperty = false; + hasComputedNumberProperty = false; + } + spreads.push(checkExpression((memberDecl as SpreadElement).target) as SpreadElementType); + continue; + } else { // TypeScript 1.0 spec (April 2014) // A get accessor declaration is processed in the same manner as @@ -10286,6 +10508,22 @@ namespace ts { } } + if (spreads.length > 0) { + if (propertiesArray.length > 0) { + const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType; + t.isDeclaredProperty = true; + spreads.push(t); + } + const propagatedFlags = getPropagatingFlagsOfTypes(spreads, /*excludeKinds*/ TypeFlags.Nullable); + const spread = getSpreadType(spreads, node.symbol); + spread.flags |= propagatedFlags; + return spread; + } + + return createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern); + } + + function createObjectLiteralType(node: ObjectLiteralExpression, hasComputedStringProperty: boolean, hasComputedNumberProperty: boolean, propertiesArray: Symbol[], propertiesTable: Map, typeFlags: TypeFlags, patternWithComputedProperties: boolean, inDestructuringPattern: boolean) { const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined; const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); @@ -10534,7 +10772,7 @@ namespace ts { elemType = checkExpression(node.tagName); } if (elemType.flags & TypeFlags.Union) { - const types = (elemType).types; + const types = (elemType).types; return getUnionType(types.map(type => { return getResolvedJsxType(node, type, elemClassType); }), /*subtypeReduction*/ true); @@ -13096,7 +13334,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { - const types = (type).types; + const types = (type).types; for (const t of types) { if (maybeTypeOfKind(t, kind)) { return true; @@ -13114,7 +13352,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.Union) { - const types = (type).types; + const types = (type).types; for (const t of types) { if (!isTypeOfKind(t, kind)) { return false; @@ -13123,7 +13361,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.Intersection) { - const types = (type).types; + const types = (type).types; for (const t of types) { if (isTypeOfKind(t, kind)) { return true; @@ -19194,7 +19432,7 @@ namespace ts { if (requestedExternalEmitHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES6) { verifyHelperSymbol(exports, "__extends", SymbolFlags.Value); } - if (requestedExternalEmitHelpers & NodeFlags.HasJsxSpreadAttributes && compilerOptions.jsx !== JsxEmit.Preserve) { + if (requestedExternalEmitHelpers & NodeFlags.HasSpreadAttribute && compilerOptions.jsx !== JsxEmit.Preserve) { verifyHelperSymbol(exports, "__assign", SymbolFlags.Value); } if (requestedExternalEmitHelpers & NodeFlags.HasDecorators) { @@ -19758,6 +19996,11 @@ namespace ts { } } + let result: TypeElement; + if (result = find(node.members, e => e.kind === SyntaxKind.SpreadTypeElement)) { + return grammarErrorOnNode(result, Diagnostics.Interface_declaration_cannot_contain_a_spread_property); + } + return false; } @@ -19805,9 +20048,23 @@ namespace ts { const GetOrSetAccessor = GetAccessor | SetAccessor; for (const prop of node.properties) { + if (prop.kind === SyntaxKind.SpreadElement) { + const target = (prop as SpreadElement).target; + switch (target.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.NullKeyword: + break; + default: + grammarErrorOnNode(target, Diagnostics.Spread_properties_must_be_identifiers_property_accesses_or_object_literals); + } + + continue; + } const name = prop.name; if (prop.kind === SyntaxKind.OmittedExpression || - name.kind === SyntaxKind.ComputedPropertyName) { + name && name.kind === SyntaxKind.ComputedPropertyName) { // If the name is not a ComputedPropertyName, the grammar checking will skip it checkGrammarComputedPropertyName(name); } @@ -20127,7 +20384,7 @@ namespace ts { } if (node.initializer) { - // Error on equals token which immediate precedes the initializer + // Error on equals token which immediately precedes the initializer return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer); } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index be4ee2fa07d98..69c2a431fc845 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1963,6 +1963,18 @@ "category": "Error", "code": 2696 }, + "Spread properties must be identifiers, property accesses, or object literals.": { + "category": "Error", + "code": 2697 + }, + "Cannot change type of property '{0}' from '{1}' to '{2}'.": { + "category": "Error", + "code": 2698 + }, + "Interface declaration cannot contain a spread property.": { + "category": "Error", + "code": 2699 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1aec63bc588ca..ae88b6d948b5b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -74,6 +74,11 @@ namespace ts { visitNode(cbNode, (node).questionToken) || visitNode(cbNode, (node).equalsToken) || visitNode(cbNode, (node).objectAssignmentInitializer); + case SyntaxKind.SpreadElement: + return visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).target); + case SyntaxKind.SpreadTypeElement: + return visitNode(cbNode, (node as SpreadTypeElement).type); case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -1262,7 +1267,7 @@ namespace ts { // which would be a candidate for improved error reporting. return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); case ParsingContext.ObjectLiteralMembers: - return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || isLiteralPropertyName(); + return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); case ParsingContext.ObjectBindingElements: return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); case ParsingContext.HeritageClauseElement: @@ -2328,6 +2333,10 @@ namespace ts { if (token() === SyntaxKind.OpenBracketToken) { return true; } + // spread elements are type members + if (token() === SyntaxKind.DotDotDotToken) { + return true; + } // Try to get the first property-like token following all modifiers if (isLiteralPropertyName()) { idToken = token(); @@ -2353,6 +2362,9 @@ namespace ts { if (token() === SyntaxKind.NewKeyword && lookAhead(isStartOfConstructSignature)) { return parseSignatureMember(SyntaxKind.ConstructSignature); } + if (token() === SyntaxKind.DotDotDotToken) { + return parseSpreadTypeElement(); + } const fullStart = getNodePos(); const modifiers = parseModifiers(); if (isIndexSignature()) { @@ -2361,6 +2373,14 @@ namespace ts { return parsePropertyOrMethodSignature(fullStart, modifiers); } + function parseSpreadTypeElement() { + const element = createNode(SyntaxKind.SpreadTypeElement, scanner.getStartPos()) as SpreadTypeElement; + parseTokenNode(); // parse `...` + element.type = parseType(); + parseTypeMemberSemicolon(); + return finishNode(element); + } + function isStartOfConstructSignature() { nextToken(); return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; @@ -4123,6 +4143,13 @@ namespace ts { function parseObjectLiteralElement(): ObjectLiteralElement { const fullStart = scanner.getStartPos(); + const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); + if (dotDotDotToken) { + const spreadElement = createNode(SyntaxKind.SpreadElement, fullStart); + spreadElement.dotDotDotToken = dotDotDotToken; + spreadElement.target = parseAssignmentExpressionOrHigher(); + return addJSDocComment(finishNode(spreadElement)); + } const decorators = parseDecorators(); const modifiers = parseModifiers(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e4bc9a29d5b03..cdf42ebea4ffc 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -316,6 +316,9 @@ namespace ts { // Property assignments PropertyAssignment, ShorthandPropertyAssignment, + SpreadElement, // maybe name it SpreadProperty? + SpreadTypeElement, // maybe name it SpreadTypeNode? + // Enum EnumMember, @@ -412,7 +415,7 @@ namespace ts { HasDecorators = 1 << 11, // If the file has decorators (initialized by binding) HasParamDecorators = 1 << 12, // If the file has parameter decorators (initialized by binding) HasAsyncFunctions = 1 << 13, // If the file has async functions (initialized by binding) - HasJsxSpreadAttributes = 1 << 14, // If the file as JSX spread attributes (initialized by binding) + HasSpreadAttribute = 1 << 14, // If the file as JSX spread attributes (initialized by binding) DisallowInContext = 1 << 15, // If node was parsed in a context where 'in-expressions' are not allowed YieldContext = 1 << 16, // If node was parsed in the 'yield' context created when parsing a generator DecoratorContext = 1 << 17, // If node was parsed as part of a decorator @@ -425,7 +428,7 @@ namespace ts { BlockScoped = Let | Const, ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn, - EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasJsxSpreadAttributes, + EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasSpreadAttribute, ReachabilityAndEmitFlags = ReachabilityCheckFlags | EmitHelperFlags, // Parsing context flags @@ -450,7 +453,6 @@ namespace ts { Async = 1 << 8, // Property/Method/Function Default = 1 << 9, // Function/Class (export default declaration) Const = 1 << 11, // Variable declaration - HasComputedFlags = 1 << 29, // Modifier flags have been computed AccessibilityModifier = Public | Private | Protected, @@ -635,6 +637,11 @@ namespace ts { initializer?: Expression; // Optional initializer } + // @kind(SyntaxKind.SpreadTypeElement) + export interface SpreadTypeElement extends TypeElement { + type: TypeNode; + } + // @kind(SyntaxKind.PropertyDeclaration) export interface PropertyDeclaration extends ClassElement { questionToken?: Node; // Present for use with reporting a grammar error @@ -666,6 +673,12 @@ namespace ts { objectAssignmentInitializer?: Expression; } + // @kind(SyntaxKind.SpreadElementExpression) + export interface SpreadElement extends ObjectLiteralElement { + dotDotDotToken: Node; + target: Expression; + } + // SyntaxKind.VariableDeclaration // SyntaxKind.Parameter // SyntaxKind.BindingElement @@ -2275,7 +2288,7 @@ namespace ts { instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) mapper?: TypeMapper; // Type mapper for instantiation alias referenced?: boolean; // True if alias symbol has been referenced as a value - containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property + containingType?: TypeOperatorType; // Containing union or intersection type for synthetic property hasCommonType?: boolean; // True if constituents of synthetic property all have same type isDiscriminantProperty?: boolean; // True if discriminant synthetic property resolvedExports?: SymbolTable; // Resolved exports of module @@ -2381,6 +2394,8 @@ namespace ts { ContainsAnyFunctionType = 1 << 27, // Type is or contains object literal type ThisType = 1 << 28, // This type ObjectLiteralPatternWithComputedProperties = 1 << 29, // Object literal type implied by binding pattern has computed properties + Spread = 1 << 30, // Spread types + // TODO: Move some types out to make room for Spread. /* @internal */ Nullable = Undefined | Null, @@ -2398,12 +2413,12 @@ namespace ts { EnumLike = Enum | EnumLiteral, ObjectType = Class | Interface | Reference | Tuple | Anonymous, UnionOrIntersection = Union | Intersection, - StructuredType = ObjectType | Union | Intersection, + StructuredType = ObjectType | Union | Intersection | Spread, StructuredOrTypeParameter = StructuredType | TypeParameter, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredType | TypeParameter | StringLike | NumberLike | BooleanLike | ESSymbol, + Narrowable = Any | StructuredType | TypeParameter | StringLike | NumberLike | BooleanLike | ESSymbol | Spread, NotUnionOrUnit = Any | String | Number | ESSymbol | ObjectType, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, @@ -2486,7 +2501,7 @@ namespace ts { instantiations: Map; // Generic instantiation cache } - export interface UnionOrIntersectionType extends Type { + export interface TypeOperatorType extends Type { types: Type[]; // Constituent types /* @internal */ resolvedProperties: SymbolTable; // Cache of resolved properties @@ -2494,9 +2509,19 @@ namespace ts { couldContainTypeParameters: boolean; } - export interface UnionType extends UnionOrIntersectionType { } + export interface UnionType extends TypeOperatorType { } + + export interface IntersectionType extends TypeOperatorType { } - export interface IntersectionType extends UnionOrIntersectionType { } + /* @internal */ + export interface SpreadType extends TypeOperatorType { + types: SpreadElementType[]; // Constituent types + } + + /* @internal */ + export interface SpreadElementType extends ResolvedType { + isDeclaredProperty: boolean | undefined; + } /* @internal */ // An instantiated anonymous type has a target and a mapper @@ -2506,8 +2531,8 @@ namespace ts { } /* @internal */ - // Resolved object, union, or intersection type - export interface ResolvedType extends ObjectType, UnionOrIntersectionType { + // Resolved object, spread, union, or intersection type + export interface ResolvedType extends ObjectType, TypeOperatorType { members: SymbolTable; // Properties by name properties: Symbol[]; // Properties callSignatures: Signature[]; // Call signatures of type @@ -3096,29 +3121,31 @@ namespace ts { ContainsTypeScript = 1 << 1, Jsx = 1 << 2, ContainsJsx = 1 << 3, - ES7 = 1 << 4, - ContainsES7 = 1 << 5, - ES6 = 1 << 6, - ContainsES6 = 1 << 7, - DestructuringAssignment = 1 << 8, - Generator = 1 << 9, - ContainsGenerator = 1 << 10, + Experimental = 1 << 4, + ContainsExperimental = 1 << 5, + ES7 = 1 << 6, + ContainsES7 = 1 << 7, + ES6 = 1 << 8, + ContainsES6 = 1 << 9, + DestructuringAssignment = 1 << 10, + Generator = 1 << 11, + ContainsGenerator = 1 << 12, // Markers // - Flags used to indicate that a subtree contains a specific transformation. - ContainsDecorators = 1 << 11, - ContainsPropertyInitializer = 1 << 12, - ContainsLexicalThis = 1 << 13, - ContainsCapturedLexicalThis = 1 << 14, - ContainsLexicalThisInComputedPropertyName = 1 << 15, - ContainsDefaultValueAssignments = 1 << 16, - ContainsParameterPropertyAssignments = 1 << 17, - ContainsSpreadElementExpression = 1 << 18, - ContainsComputedPropertyName = 1 << 19, - ContainsBlockScopedBinding = 1 << 20, - ContainsBindingPattern = 1 << 21, - ContainsYield = 1 << 22, - ContainsHoistedDeclarationOrCompletion = 1 << 23, + ContainsDecorators = 1 << 13, + ContainsPropertyInitializer = 1 << 14, + ContainsLexicalThis = 1 << 15, + ContainsCapturedLexicalThis = 1 << 16, + ContainsLexicalThisInComputedPropertyName = 1 << 17, + ContainsDefaultValueAssignments = 1 << 18, + ContainsParameterPropertyAssignments = 1 << 19, + ContainsSpreadElementExpression = 1 << 20, + ContainsComputedPropertyName = 1 << 21, + ContainsBlockScopedBinding = 1 << 22, + ContainsBindingPattern = 1 << 23, + ContainsYield = 1 << 24, + ContainsHoistedDeclarationOrCompletion = 1 << 25, HasComputedFlags = 1 << 29, // Transform flags have been computed. @@ -3126,6 +3153,7 @@ namespace ts { // - Bitmasks that are used to assert facts about the syntax of a node and its subtree. AssertTypeScript = TypeScript | ContainsTypeScript, AssertJsx = Jsx | ContainsJsx, + AssertExperimental = Experimental | ContainsExperimental, AssertES7 = ES7 | ContainsES7, AssertES6 = ES6 | ContainsES6, AssertGenerator = Generator | ContainsGenerator, @@ -3133,7 +3161,7 @@ namespace ts { // Scope Exclusions // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. - NodeExcludes = TypeScript | Jsx | ES7 | ES6 | DestructuringAssignment | Generator | HasComputedFlags, + NodeExcludes = TypeScript | Jsx | Experimental | ES7 | ES6 | DestructuringAssignment | Generator | HasComputedFlags, ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7a22c5634d84f..67ea182bf9868 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3740,6 +3740,7 @@ namespace ts { const kind = node.kind; return kind === SyntaxKind.PropertyAssignment || kind === SyntaxKind.ShorthandPropertyAssignment + || kind === SyntaxKind.SpreadElement || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor diff --git a/src/harness/harness.ts b/src/harness/harness.ts index b4fd8736b2f7d..3d050b2cf2c6c 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1463,7 +1463,7 @@ namespace Harness { } if (typesError && symbolsError) { - throw new Error(typesError.message + ts.sys.newLine + symbolsError.message); + throw new Error(typesError.message + Harness.IO.newLine() + symbolsError.message); } if (typesError) { diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index dcda3e40b1a67..8766937c00851 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -458,7 +458,7 @@ namespace ts.FindAllReferences { return [localParentType.symbol]; } else if (localParentType.flags & TypeFlags.UnionOrIntersection) { - return getSymbolsForClassAndInterfaceComponents(localParentType); + return getSymbolsForClassAndInterfaceComponents(localParentType); } } } @@ -630,13 +630,13 @@ namespace ts.FindAllReferences { } } - function getSymbolsForClassAndInterfaceComponents(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] { + function getSymbolsForClassAndInterfaceComponents(type: TypeOperatorType, result: Symbol[] = []): Symbol[] { for (const componentType of type.types) { if (componentType.symbol && componentType.symbol.getFlags() & (SymbolFlags.Class | SymbolFlags.Interface)) { result.push(componentType.symbol); } if (componentType.getFlags() & TypeFlags.UnionOrIntersection) { - getSymbolsForClassAndInterfaceComponents(componentType, result); + getSymbolsForClassAndInterfaceComponents(componentType, result); } } return result; From 7004652a0a714364eb627591df5e288220c58226 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 09:31:34 -0700 Subject: [PATCH 02/85] Declaration emit spread types and downlevel spread --- src/compiler/declarationEmitter.ts | 10 +++ src/compiler/emitter.ts | 2 +- src/compiler/transformer.ts | 4 +- src/compiler/transformers/es7.ts | 3 +- src/compiler/transformers/experimental.ts | 80 +++++++++++++++++++++++ 5 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 src/compiler/transformers/experimental.ts diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index a015ad79b9791..58ed2211160bd 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1121,6 +1121,14 @@ namespace ts { writeLine(); } + + function emitSpreadTypeElement(type: SpreadTypeElement) { + write("..."); + emitType(type.type); + write(";"); + writeLine(); + } + function emitVariableDeclaration(node: VariableDeclaration) { // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted // so there is no check needed to see if declaration is visible @@ -1702,6 +1710,8 @@ namespace ts { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: return emitPropertyDeclaration(node); + case SyntaxKind.SpreadTypeElement: + return emitSpreadTypeElement(node as SpreadTypeElement); case SyntaxKind.EnumMember: return emitEnumMemberDeclaration(node); case SyntaxKind.ExportAssignment: diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 14e743cf59f76..cd00f7ad76905 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2195,7 +2195,7 @@ const _super = (function (geti, seti) { helpersEmitted = true; } - if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasJsxSpreadAttributes)) { + if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasSpreadAttribute)) { writeLines(assignHelper); assignEmitted = true; } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 6242a2f23474c..2fa57730bf085 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -1,6 +1,7 @@ /// /// /// +/// /// /// /// @@ -176,6 +177,7 @@ namespace ts { transformers.push(transformJsx); } + transformers.push(transformExperimental); transformers.push(transformES7); if (languageVersion < ScriptTarget.ES6) { @@ -629,4 +631,4 @@ namespace ts { return t => t; } } -} \ No newline at end of file +} diff --git a/src/compiler/transformers/es7.ts b/src/compiler/transformers/es7.ts index 5d848bc608bad..5aaaacb9ecd7a 100644 --- a/src/compiler/transformers/es7.ts +++ b/src/compiler/transformers/es7.ts @@ -28,7 +28,6 @@ namespace ts { switch (node.kind) { case SyntaxKind.BinaryExpression: return visitBinaryExpression(node); - default: Debug.failBadSyntaxKind(node); return visitEachChild(node, visitor, context); @@ -94,4 +93,4 @@ namespace ts { } } } -} \ No newline at end of file +} diff --git a/src/compiler/transformers/experimental.ts b/src/compiler/transformers/experimental.ts new file mode 100644 index 0000000000000..715cf91afd3e6 --- /dev/null +++ b/src/compiler/transformers/experimental.ts @@ -0,0 +1,80 @@ +/// +/// + +/*@internal*/ +namespace ts { + export function transformExperimental(context: TransformationContext) { + return transformSourceFile; + + function transformSourceFile(node: SourceFile) { + return visitEachChild(node, visitor, context); + } + + function visitor(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.Experimental) { + return visitorWorker(node); + } + else if (node.transformFlags & TransformFlags.ContainsExperimental) { + return visitEachChild(node, visitor, context); + } + else { + return node; + } + } + + function visitorWorker(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.ObjectLiteralExpression: + return visitObjectLiteralExpression(node as ObjectLiteralExpression); + default: + Debug.failBadSyntaxKind(node); + return visitEachChild(node, visitor, context); + } + } + + function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] { + let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; + const objects: Expression[] = []; + for (const e of elements) { + if (e.kind === SyntaxKind.SpreadElement) { + if (chunkObject) { + objects.push(createObjectLiteral(chunkObject)); + chunkObject = undefined; + } + const target = (e as SpreadElement).target; + objects.push(visitNode(target, visitor, isExpression)); + } + else { + if (!chunkObject) { + chunkObject = []; + } + if (e.kind === SyntaxKind.PropertyAssignment) { + const p = e as PropertyAssignment; + chunkObject.push(createPropertyAssignment(p.name, visitNode(p.initializer, visitor, isExpression))); + } + else { + chunkObject.push(e as ShorthandPropertyAssignment); + } + } + } + if (chunkObject) { + objects.push(createObjectLiteral(chunkObject)); + } + + return objects; + } + + function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression { + // spread elements emit like so: + // non-spread elements are chunked together into object literals, and then all are passed to __assign: + // { a, ...o, b } => __assign({a}, o, {b}); + // If the first element is a spread element, then the first argument to __assign is {}: + // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2) + const objects = chunkObjectLiteralElements(node.properties); + if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { + objects.unshift(createObjectLiteral()); + } + return createCall(createIdentifier("__assign"), undefined, objects); + } + } +} From bf866cea7b82f8c22d648acbe6815cfa9632d8db Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 09:32:23 -0700 Subject: [PATCH 03/85] Update build files --- Jakefile.js | 2 ++ src/compiler/tsconfig.json | 1 + src/harness/tsconfig.json | 1 + src/services/tsconfig.json | 1 + 4 files changed, 5 insertions(+) diff --git a/Jakefile.js b/Jakefile.js index c62a4ffd6ce0e..6b749d4a4ef83 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -72,6 +72,7 @@ var compilerSources = [ "transformers/module/system.ts", "transformers/module/module.ts", "transformers/jsx.ts", + "transformers/experimental.ts", "transformers/es7.ts", "transformers/generators.ts", "transformers/es6.ts", @@ -106,6 +107,7 @@ var servicesSources = [ "transformers/module/system.ts", "transformers/module/module.ts", "transformers/jsx.ts", + "transformers/experimental.ts", "transformers/es7.ts", "transformers/generators.ts", "transformers/es6.ts", diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index f128c994af12b..9681aba0d8f1c 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -24,6 +24,7 @@ "visitor.ts", "transformers/ts.ts", "transformers/jsx.ts", + "transformers/experimental.ts", "transformers/es7.ts", "transformers/es6.ts", "transformers/generators.ts", diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 8444d1d4a751e..fda4c68272ef1 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -26,6 +26,7 @@ "../compiler/visitor.ts", "../compiler/transformers/ts.ts", "../compiler/transformers/jsx.ts", + "../compiler/transformers/experimental.ts", "../compiler/transformers/es7.ts", "../compiler/transformers/es6.ts", "../compiler/transformers/generators.ts", diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 58312c6f38ff3..8d612fb7a7557 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -25,6 +25,7 @@ "../compiler/visitor.ts", "../compiler/transformers/ts.ts", "../compiler/transformers/jsx.ts", + "../compiler/transformers/experimental.ts", "../compiler/transformers/es7.ts", "../compiler/transformers/es6.ts", "../compiler/transformers/generators.ts", From 0fea59f642604ecd105c424deae982a73b4032c7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 09:33:08 -0700 Subject: [PATCH 04/85] Add spread tests --- ...uringObjectBindingPatternAndAssignment3.ts | 5 +- .../es6/destructuring/interfaceSpread.ts | 8 ++ .../conformance/types/spread/objectSpread.ts | 96 +++++++++++++++++++ .../types/spread/objectSpreadGeneric.ts | 40 ++++++++ .../types/spread/objectSpreadNegative.ts | 49 ++++++++++ .../types/spread/objectSpreadNegativeParse.ts | 4 + .../completionListForObjectSpread.ts | 35 +++++++ .../fourslash/findAllRefsForObjectSpread.ts | 12 +++ .../fourslash/goToDefinitionObjectSpread.ts | 7 ++ tests/cases/fourslash/renameObjectSpread.ts | 18 ++++ 10 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 tests/cases/conformance/es6/destructuring/interfaceSpread.ts create mode 100644 tests/cases/conformance/types/spread/objectSpread.ts create mode 100644 tests/cases/conformance/types/spread/objectSpreadGeneric.ts create mode 100644 tests/cases/conformance/types/spread/objectSpreadNegative.ts create mode 100644 tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts create mode 100644 tests/cases/fourslash/completionListForObjectSpread.ts create mode 100644 tests/cases/fourslash/findAllRefsForObjectSpread.ts create mode 100644 tests/cases/fourslash/goToDefinitionObjectSpread.ts create mode 100644 tests/cases/fourslash/renameObjectSpread.ts diff --git a/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts index 2b3192bc9a2c3..1e2bc1e68b433 100644 --- a/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts +++ b/tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts @@ -3,8 +3,5 @@ var {h?} = { h?: 1 }; var {i}: string | number = { i: 2 }; var {i1}: string | number| {} = { i1: 2 }; var { f2: {f21} = { f212: "string" } }: any = undefined; -var { ...d1 } = { - a: 1, b: 1, d1: 9, e: 10 -} var {1} = { 1 }; -var {"prop"} = { "prop": 1 }; \ No newline at end of file +var {"prop"} = { "prop": 1 }; diff --git a/tests/cases/conformance/es6/destructuring/interfaceSpread.ts b/tests/cases/conformance/es6/destructuring/interfaceSpread.ts new file mode 100644 index 0000000000000..a92a188e1a884 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/interfaceSpread.ts @@ -0,0 +1,8 @@ +interface Congealed { + ...T + ...U +} + +let sandwich: Congealed<{jam: number }, { peanutButter: number }>; +sandwich.jam; +sandwich.peanutButter; diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts new file mode 100644 index 0000000000000..9828e86f0a6bc --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -0,0 +1,96 @@ +// @target: es5 +let o = { a: 1, b: 'no' } +let o2 = { b: 'yes', c: true } +let swap = { a: 'yes', b: -1 }; + +let addAfter: { a: number, b: string, c: boolean } = + { ...o, c: false } +let addBefore: { a: number, b: string, c: boolean } = + { c: false, ...o } +// Note: ignore still changes the order that properties are printed +let ignore: { a: number, b: string } = + { b: 'ignored', ...o } +let override: { a: number, b: string } = + { ...o, b: 'override' } +let nested: { a: number, b: boolean, c: string } = + { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } +let combined: { a: number, b: string, c: boolean } = + { ...o, ...o2 } +let combinedBefore: { a: number, b: string, c: boolean } = + { b: 'ok', ...o, ...o2 } +let combinedMid: { a: number, b: string, c: boolean } = + { ...o, b: 'ok', ...o2 } +let combinedAfter: { a: number, b: string, c: boolean } = + { ...o, ...o2, b: 'ok' } +let combinedNested: { a: number, b: boolean, c: string, d: string } = + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +let combinedNestedChangeType: { a: number, b: boolean, c: number } = + { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } +let propertyNested: { a: { a: number, b: string } } = + { a: { ... o } } +// accessors don't copy the descriptor +// (which means that readonly getters become read/write properties) +let op = { get a () { return 6 } }; +let getter: { a: number, c: number } = + { ...op, c: 7 } +getter.a = 12; + +// null and undefined are just skipped +let spreadNull: { a: number } = + { a: 7, ...null } +let spreadUndefined: { a: number } = + { a: 7, ...undefined } + +// methods are not enumerable +class C { p = 1; m() { } } +let c: C = new C() +let spreadC: { p: number } = { ...c } + +// own methods are enumerable +let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; +cplus.plus(); + +// new field's type conflicting with existing field is OK +let changeTypeAfter: { a: string, b: string } = + { ...o, a: 'wrong type?' } +let changeTypeBefore: { a: number, b: string } = + { a: 'wrong type?', ...o }; +let changeTypeBoth: { a: string, b: number } = + { ...o, ...swap }; + +// optional +let definiteBoolean: { sn: boolean }; +let definiteString: { sn: string }; +let optionalString: { sn?: string }; +let optionalNumber: { sn?: number }; +let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; + +// computed property +let computedFirst: { a: number, b: string, "before everything": number } = + { ['before everything']: 12, ...o, b: 'yes' } +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } +let computedAfter: { a: number, b: string, "at the end": number } = + { ...o, b: 'yeah', ['at the end']: 14 } +// shortcut syntax +let a = 12; +let shortCutted: { a: number, b: string } = { ...o, a } + +// generics +function f(t: T, u: U): { id: string, ...T, ...U } { + return { id: 'id', ...t, ...u }; +} +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) +let overwriteId: { id: boolean, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) + +class D { m() { }; q = 2; } +let classesAreWrong: { id: string, ...C, ...D } = + f(new C(), new D()) diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts new file mode 100644 index 0000000000000..552142004b70f --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts @@ -0,0 +1,40 @@ +function f(t: T, u: U, v: V): void { + let o: { ...T, ...U, ...V }; + const same: { ...T, ...U, ...V } = o; // ok + const reversed: { ...V, ...U, ...T } = o; // error, reversed + const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed + const missingT: { ...U, ...V } = o; // error, missing T + const missingU: { ...T, ...V } = o; // error, missing U + const missingV: { ...T, ...U } = o; // error, missing V + const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok + const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // ok + + const emptyTarget: { } = { ...t, ...u } // ok + const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) + + let optionalNumber: { sn?: number }; + let optionalString: { sn?: string }; + let optionalBoolean: { sn?: boolean }; + const unionCutoff: { ...T, sn?: number | string | boolean } = + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } // ok + unionCutoff.sn; // ok + const optionalCutoff = { ...t, ...optionalNumber }; // ok + optionalCutoff.sn; // ok + + const interspersed: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, second: '2', ...u, third: '3' }; // ok + const interspersedMissingU: { first: string, second: string, ...T, third: string } = + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing + const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + + + const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found + const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found + const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found +} diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts new file mode 100644 index 0000000000000..4691e45a17df3 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -0,0 +1,49 @@ +// @target: es5 +let o = { a: 1, b: 'no' } + +/// private propagates +class PrivateOptionalX { + private x?: number; +} +class PublicX { + public x: number; +} +let privateOptionalx: PrivateOptionalX; +let publicx: PublicX; +let o3 = { ...publicx, ...privateOptionalx }; +let sn: string | number = o3.x; // error, x is private +let optionalString: { sn?: string }; +let optionalNumber: { sn?: number }; +let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; +// error, 'sn' is optional in source, required in target + +// assignability as target +interface Bool { b: boolean }; +interface Str { s: string }; +let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' +let b: Bool; +spread = b; // error, missing 's' + +// expressions are not allowed +let o1 = { ...1 + 1 }; +let o2 = { ...(1 + 1) }; + +// literal repeats are not allowed, but spread repeats are fine +let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } +let duplicatedSpread = { ...o, ...o } + +// write-only properties get skipped +let setterOnly = { ...{ set b (bad: number) { } } }; +setterOnly.b = 12; // error, 'b' does not exist + +// methods are skipped because they aren't enumerable +class C { p = 1; m() { } } +let c: C = new C() +let spreadC = { ...c } +spreadC.m(); // error 'm' is not in '{ ... c }' + +let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; +callableConstructableSpread(12); // error, no call signature +new callableConstructableSpread(12); // error, no construct signature + +let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions diff --git a/tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts b/tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts new file mode 100644 index 0000000000000..47fd787ec9a35 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts @@ -0,0 +1,4 @@ +let o7 = { ...o? }; +let o8 = { ...*o }; +let o9 = { ...matchMedia() { }}; +let o10 = { ...get x() { return 12; }}; diff --git a/tests/cases/fourslash/completionListForObjectSpread.ts b/tests/cases/fourslash/completionListForObjectSpread.ts new file mode 100644 index 0000000000000..ca96797195c15 --- /dev/null +++ b/tests/cases/fourslash/completionListForObjectSpread.ts @@ -0,0 +1,35 @@ +/// +////let o = { a: 1, b: 'no' } +////let o2 = { b: 'yes', c: true } +////let swap = { a: 'yes', b: -1 }; +////let addAfter: { a: number, b: string, c: boolean } = +//// { ...o, c: false } +////let addBefore: { a: number, b: string, c: boolean } = +//// { c: false, ...o } +////let ignore: { a: number, b: string } = +//// { b: 'ignored', ...o } +////ignore./*1*/a; +////let combinedNestedChangeType: { a: number, b: boolean, c: number } = +//// { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } +////combinedNestedChangeType./*2*/a; +////let spreadNull: { a: number } = +//// { a: 7, ...null } +////let spreadUndefined: { a: number } = +//// { a: 7, ...undefined } +////spreadNull./*3*/a; +////spreadUndefined./*4*/a; +goTo.marker('1'); +verify.memberListContains('a', '(property) a: number'); +verify.memberListContains('b', '(property) b: string'); +verify.memberListCount(2); +goTo.marker('2'); +verify.memberListContains('a', '(property) a: number'); +verify.memberListContains('b', '(property) b: boolean'); +verify.memberListContains('c', '(property) c: number'); +verify.memberListCount(3); +goTo.marker('3'); +verify.memberListContains('a', '(property) a: number'); +verify.memberListCount(1); +goTo.marker('4'); +verify.memberListContains('a', '(property) a: number'); +verify.memberListCount(1); diff --git a/tests/cases/fourslash/findAllRefsForObjectSpread.ts b/tests/cases/fourslash/findAllRefsForObjectSpread.ts new file mode 100644 index 0000000000000..fe0a7f9c20195 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForObjectSpread.ts @@ -0,0 +1,12 @@ +/// + +////interface A1 { [|a|]: number }; +////interface A2 { [|a|]?: number }; +////let a12: { ...A1, ...A2 }; +////a12.[|a|]; +const ranges = test.ranges(); +// members of spread types only refer to themselves and the resulting property +verify.referencesOf(ranges[0], [ranges[0], ranges[2]]); +verify.referencesOf(ranges[1], [ranges[1], ranges[2]]); +// but the resulting property refers to everything +verify.referencesOf(ranges[2], ranges); diff --git a/tests/cases/fourslash/goToDefinitionObjectSpread.ts b/tests/cases/fourslash/goToDefinitionObjectSpread.ts new file mode 100644 index 0000000000000..64623c36cb76b --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionObjectSpread.ts @@ -0,0 +1,7 @@ +/// + +////interface A1 { /*1*/a: number }; +////interface A2 { /*2*/a?: number }; +////let a12: { ...A1, ...A2 }; +////a12.a/*3*/; +verify.goToDefinition('3', [ '1', '2' ]); diff --git a/tests/cases/fourslash/renameObjectSpread.ts b/tests/cases/fourslash/renameObjectSpread.ts new file mode 100644 index 0000000000000..a2c640361e59c --- /dev/null +++ b/tests/cases/fourslash/renameObjectSpread.ts @@ -0,0 +1,18 @@ +/// + +////interface A1 { [|a|]: number }; +////interface A2 { [|a|]?: number }; +////let a12: { ...A1, ...A2 }; +////a12.[|a|]; +const ranges = test.ranges(); +verify.assertHasRanges(ranges); + +// A1 unions with A2, so rename A1.a and a12.a +goTo.position(ranges[0].start); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, [ranges[0], ranges[2]]); +// A1 unions with A2, so rename A2.a and a12.a +goTo.position(ranges[1].start); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, [ranges[1], ranges[2]]); +// a12.a unions A1.a and A2.a, so rename A1.a, A2.a and a12.a +goTo.position(ranges[2].start); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, [ranges[0], ranges[1], ranges[2]]); From c8db211d90424abd949805264f724dc4adbbb53e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 09:33:27 -0700 Subject: [PATCH 05/85] Update baselines --- ...ectBindingPatternAndAssignment3.errors.txt | 26 +- ...uringObjectBindingPatternAndAssignment3.js | 9 +- .../duplicateObjectLiteralProperty.errors.txt | 8 +- .../reference/interfaceSpread.errors.txt | 21 + tests/baselines/reference/interfaceSpread.js | 15 + .../lastPropertyInLiteralWins.errors.txt | 8 +- .../reference/memberOverride.errors.txt | 5 +- .../reference/objectLiteralErrors.errors.txt | 5 +- ...tiesErrorFromNotUsingIdentifier.errors.txt | 8 +- tests/baselines/reference/objectSpread.js | 181 ++++++ .../baselines/reference/objectSpread.symbols | 369 ++++++++++++ tests/baselines/reference/objectSpread.types | 530 ++++++++++++++++++ .../reference/objectSpreadGeneric.errors.txt | 80 +++ .../reference/objectSpreadGeneric.js | 79 +++ .../reference/objectSpreadNegative.errors.txt | 93 +++ .../reference/objectSpreadNegative.js | 108 ++++ .../objectSpreadNegativeParse.errors.txt | 35 ++ .../reference/objectSpreadNegativeParse.js | 21 + 18 files changed, 1569 insertions(+), 32 deletions(-) create mode 100644 tests/baselines/reference/interfaceSpread.errors.txt create mode 100644 tests/baselines/reference/interfaceSpread.js create mode 100644 tests/baselines/reference/objectSpread.js create mode 100644 tests/baselines/reference/objectSpread.symbols create mode 100644 tests/baselines/reference/objectSpread.types create mode 100644 tests/baselines/reference/objectSpreadGeneric.errors.txt create mode 100644 tests/baselines/reference/objectSpreadGeneric.js create mode 100644 tests/baselines/reference/objectSpreadNegative.errors.txt create mode 100644 tests/baselines/reference/objectSpreadNegative.js create mode 100644 tests/baselines/reference/objectSpreadNegativeParse.errors.txt create mode 100644 tests/baselines/reference/objectSpreadNegativeParse.js diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.errors.txt b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.errors.txt index bb4b79987e349..33344b9b5eb00 100644 --- a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.errors.txt +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.errors.txt @@ -5,16 +5,12 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(4,6): error TS2459: Type 'string | number | {}' has no property 'i1' and no string index signature. tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(5,12): error TS2525: Initializer provides no value for this binding element and the binding element has no default value. tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(5,21): error TS2353: Object literal may only specify known properties, and 'f212' does not exist in type '{ f21: any; }'. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(6,7): error TS1180: Property destructuring pattern expected. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,5): error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ d1: any; }'. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,11): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type '{ d1: any; }'. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,24): error TS2353: Object literal may only specify known properties, and 'e' does not exist in type '{ d1: any; }'. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(9,7): error TS1005: ':' expected. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(9,15): error TS1005: ':' expected. -tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(10,12): error TS1005: ':' expected. +tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(6,7): error TS1005: ':' expected. +tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(6,15): error TS1005: ':' expected. +tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,12): error TS1005: ':' expected. -==== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts (13 errors) ==== +==== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts (9 errors) ==== // Error var {h?} = { h?: 1 }; ~ @@ -33,17 +29,6 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs !!! error TS2525: Initializer provides no value for this binding element and the binding element has no default value. ~~~~ !!! error TS2353: Object literal may only specify known properties, and 'f212' does not exist in type '{ f21: any; }'. - var { ...d1 } = { - ~~~ -!!! error TS1180: Property destructuring pattern expected. - a: 1, b: 1, d1: 9, e: 10 - ~ -!!! error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ d1: any; }'. - ~ -!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type '{ d1: any; }'. - ~ -!!! error TS2353: Object literal may only specify known properties, and 'e' does not exist in type '{ d1: any; }'. - } var {1} = { 1 }; ~ !!! error TS1005: ':' expected. @@ -51,4 +36,5 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs !!! error TS1005: ':' expected. var {"prop"} = { "prop": 1 }; ~ -!!! error TS1005: ':' expected. \ No newline at end of file +!!! error TS1005: ':' expected. + \ No newline at end of file diff --git a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.js b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.js index 77288e6a5427a..0872a71c73bd8 100644 --- a/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.js +++ b/tests/baselines/reference/destructuringObjectBindingPatternAndAssignment3.js @@ -4,11 +4,9 @@ var {h?} = { h?: 1 }; var {i}: string | number = { i: 2 }; var {i1}: string | number| {} = { i1: 2 }; var { f2: {f21} = { f212: "string" } }: any = undefined; -var { ...d1 } = { - a: 1, b: 1, d1: 9, e: 10 -} var {1} = { 1 }; -var {"prop"} = { "prop": 1 }; +var {"prop"} = { "prop": 1 }; + //// [destructuringObjectBindingPatternAndAssignment3.js] // Error @@ -16,8 +14,5 @@ var h = { h: 1 }.h; var i = { i: 2 }.i; var i1 = { i1: 2 }.i1; var _a = undefined.f2, f21 = (_a === void 0 ? { f212: "string" } : _a).f21; -var d1 = { - a: 1, b: 1, d1: 9, e: 10 -}.d1; var = { 1: }[1]; var = { "prop": 1 }["prop"]; diff --git a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt index abc56a6f8fce7..926a707122293 100644 --- a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt +++ b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt @@ -1,6 +1,8 @@ tests/cases/compiler/duplicateObjectLiteralProperty.ts(4,5): error TS2300: Duplicate identifier 'a'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(5,5): error TS2300: Duplicate identifier '\u0061'. +tests/cases/compiler/duplicateObjectLiteralProperty.ts(5,5): error TS2698: Cannot change type of property 'a' from 'number' to 'string'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(6,5): error TS2300: Duplicate identifier 'a'. +tests/cases/compiler/duplicateObjectLiteralProperty.ts(6,5): error TS2698: Cannot change type of property 'a' from 'string' to '{ c: number; }'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(8,9): error TS2300: Duplicate identifier '"c"'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(14,9): error TS2300: Duplicate identifier 'a'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(15,9): error TS2300: Duplicate identifier 'a'. @@ -8,7 +10,7 @@ tests/cases/compiler/duplicateObjectLiteralProperty.ts(16,9): error TS1118: An o tests/cases/compiler/duplicateObjectLiteralProperty.ts(16,9): error TS2300: Duplicate identifier 'a'. -==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (8 errors) ==== +==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (10 errors) ==== var x = { a: 1, b: true, // OK @@ -18,9 +20,13 @@ tests/cases/compiler/duplicateObjectLiteralProperty.ts(16,9): error TS2300: Dupl \u0061: "ss", // Duplicate ~~~~~~ !!! error TS2300: Duplicate identifier '\u0061'. + ~~~~~~ +!!! error TS2698: Cannot change type of property 'a' from 'number' to 'string'. a: { ~ !!! error TS2300: Duplicate identifier 'a'. + ~ +!!! error TS2698: Cannot change type of property 'a' from 'string' to '{ c: number; }'. c: 1, "c": 56, // Duplicate ~~~ diff --git a/tests/baselines/reference/interfaceSpread.errors.txt b/tests/baselines/reference/interfaceSpread.errors.txt new file mode 100644 index 0000000000000..27aab11491c5a --- /dev/null +++ b/tests/baselines/reference/interfaceSpread.errors.txt @@ -0,0 +1,21 @@ +tests/cases/conformance/es6/destructuring/interfaceSpread.ts(2,5): error TS2699: Interface declaration cannot contain a spread property. +tests/cases/conformance/es6/destructuring/interfaceSpread.ts(7,10): error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. +tests/cases/conformance/es6/destructuring/interfaceSpread.ts(8,10): error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. + + +==== tests/cases/conformance/es6/destructuring/interfaceSpread.ts (3 errors) ==== + interface Congealed { + ...T + ~~~~ +!!! error TS2699: Interface declaration cannot contain a spread property. + ...U + } + + let sandwich: Congealed<{jam: number }, { peanutButter: number }>; + sandwich.jam; + ~~~ +!!! error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. + sandwich.peanutButter; + ~~~~~~~~~~~~ +!!! error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. + \ No newline at end of file diff --git a/tests/baselines/reference/interfaceSpread.js b/tests/baselines/reference/interfaceSpread.js new file mode 100644 index 0000000000000..89f2531436667 --- /dev/null +++ b/tests/baselines/reference/interfaceSpread.js @@ -0,0 +1,15 @@ +//// [interfaceSpread.ts] +interface Congealed { + ...T + ...U +} + +let sandwich: Congealed<{jam: number }, { peanutButter: number }>; +sandwich.jam; +sandwich.peanutButter; + + +//// [interfaceSpread.js] +var sandwich; +sandwich.jam; +sandwich.peanutButter; diff --git a/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt b/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt index 2b4a694975b4c..c8844f2c5721f 100644 --- a/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt +++ b/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt @@ -4,10 +4,12 @@ tests/cases/compiler/lastPropertyInLiteralWins.ts(7,6): error TS2345: Argument o Types of parameters 'num' and 'str' are incompatible. Type 'string' is not assignable to type 'number'. tests/cases/compiler/lastPropertyInLiteralWins.ts(9,5): error TS2300: Duplicate identifier 'thunk'. +tests/cases/compiler/lastPropertyInLiteralWins.ts(9,5): error TS2698: Cannot change type of property 'thunk' from '(str: string) => void' to '(num: number) => void'. tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2300: Duplicate identifier 'thunk'. +tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2698: Cannot change type of property 'thunk' from '(num: number) => void' to '(str: string) => void'. -==== tests/cases/compiler/lastPropertyInLiteralWins.ts (3 errors) ==== +==== tests/cases/compiler/lastPropertyInLiteralWins.ts (5 errors) ==== interface Thing { thunk: (str: string) => void; } @@ -22,6 +24,8 @@ tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2300: Duplicate ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~ !!! error TS2300: Duplicate identifier 'thunk'. + ~~~~~ +!!! error TS2698: Cannot change type of property 'thunk' from '(str: string) => void' to '(num: number) => void'. }); ~ !!! error TS2345: Argument of type '{ thunk: (num: number) => void; }' is not assignable to parameter of type 'Thing'. @@ -35,5 +39,7 @@ tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2300: Duplicate thunk: (str: string) => {} ~~~~~ !!! error TS2300: Duplicate identifier 'thunk'. + ~~~~~ +!!! error TS2698: Cannot change type of property 'thunk' from '(num: number) => void' to '(str: string) => void'. }); \ No newline at end of file diff --git a/tests/baselines/reference/memberOverride.errors.txt b/tests/baselines/reference/memberOverride.errors.txt index 15c4b2ad37bb8..355db0015057f 100644 --- a/tests/baselines/reference/memberOverride.errors.txt +++ b/tests/baselines/reference/memberOverride.errors.txt @@ -1,7 +1,8 @@ tests/cases/compiler/memberOverride.ts(5,5): error TS2300: Duplicate identifier 'a'. +tests/cases/compiler/memberOverride.ts(5,5): error TS2698: Cannot change type of property 'a' from 'string' to 'number'. -==== tests/cases/compiler/memberOverride.ts (1 errors) ==== +==== tests/cases/compiler/memberOverride.ts (2 errors) ==== // An object initialiser accepts the first definition for the same property with a different type signature // Should compile, since the second declaration of a overrides the first var x = { @@ -9,6 +10,8 @@ tests/cases/compiler/memberOverride.ts(5,5): error TS2300: Duplicate identifier a: 5 ~ !!! error TS2300: Duplicate identifier 'a'. + ~ +!!! error TS2698: Cannot change type of property 'a' from 'string' to 'number'. } var n: number = x.a; \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralErrors.errors.txt b/tests/baselines/reference/objectLiteralErrors.errors.txt index 234ac24a8fdc5..f70f255df05b8 100644 --- a/tests/baselines/reference/objectLiteralErrors.errors.txt +++ b/tests/baselines/reference/objectLiteralErrors.errors.txt @@ -1,6 +1,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(3,18): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(4,19): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(5,18): error TS2300: Duplicate identifier 'a'. +tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(5,18): error TS2698: Cannot change type of property 'a' from 'number' to 'string'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(6,21): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(7,19): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(8,18): error TS2300: Duplicate identifier ''a''. @@ -78,7 +79,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,16) tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,55): error TS2380: 'get' and 'set' accessor must have the same type. -==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (78 errors) ==== +==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (79 errors) ==== // Multiple properties with the same name var e1 = { a: 0, a: 0 }; @@ -90,6 +91,8 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,55) var e3 = { a: 0, a: '' }; ~ !!! error TS2300: Duplicate identifier 'a'. + ~ +!!! error TS2698: Cannot change type of property 'a' from 'number' to 'string'. var e4 = { a: true, a: false }; ~ !!! error TS2300: Duplicate identifier 'a'. diff --git a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt index 5fa8a12e87559..cbe19cab2d25b 100644 --- a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt +++ b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt @@ -8,12 +8,14 @@ tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPr tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(10,10): error TS1005: ':' expected. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(12,1): error TS1005: ':' expected. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(15,6): error TS1005: ':' expected. +tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(16,5): error TS2698: Cannot change type of property 'a' from 'any' to 'string[]'. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(16,6): error TS1005: ':' expected. +tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(17,5): error TS2698: Cannot change type of property 'a' from 'string[]' to 'number[]'. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(17,6): error TS1005: ':' expected. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(20,17): error TS1005: ':' expected. -==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts (13 errors) ==== +==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts (15 errors) ==== // errors var y = { "stringLiteral", @@ -50,9 +52,13 @@ tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPr ~ !!! error TS1005: ':' expected. a["ss"], + ~ +!!! error TS2698: Cannot change type of property 'a' from 'any' to 'string[]'. ~ !!! error TS1005: ':' expected. a[1], + ~ +!!! error TS2698: Cannot change type of property 'a' from 'string[]' to 'number[]'. ~ !!! error TS1005: ':' expected. }; diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js new file mode 100644 index 0000000000000..a59577fe9dece --- /dev/null +++ b/tests/baselines/reference/objectSpread.js @@ -0,0 +1,181 @@ +//// [objectSpread.ts] +let o = { a: 1, b: 'no' } +let o2 = { b: 'yes', c: true } +let swap = { a: 'yes', b: -1 }; + +let addAfter: { a: number, b: string, c: boolean } = + { ...o, c: false } +let addBefore: { a: number, b: string, c: boolean } = + { c: false, ...o } +// Note: ignore still changes the order that properties are printed +let ignore: { a: number, b: string } = + { b: 'ignored', ...o } +let override: { a: number, b: string } = + { ...o, b: 'override' } +let nested: { a: number, b: boolean, c: string } = + { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } +let combined: { a: number, b: string, c: boolean } = + { ...o, ...o2 } +let combinedBefore: { a: number, b: string, c: boolean } = + { b: 'ok', ...o, ...o2 } +let combinedMid: { a: number, b: string, c: boolean } = + { ...o, b: 'ok', ...o2 } +let combinedAfter: { a: number, b: string, c: boolean } = + { ...o, ...o2, b: 'ok' } +let combinedNested: { a: number, b: boolean, c: string, d: string } = + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +let combinedNestedChangeType: { a: number, b: boolean, c: number } = + { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } +let propertyNested: { a: { a: number, b: string } } = + { a: { ... o } } +// accessors don't copy the descriptor +// (which means that readonly getters become read/write properties) +let op = { get a () { return 6 } }; +let getter: { a: number, c: number } = + { ...op, c: 7 } +getter.a = 12; + +// null and undefined are just skipped +let spreadNull: { a: number } = + { a: 7, ...null } +let spreadUndefined: { a: number } = + { a: 7, ...undefined } + +// methods are not enumerable +class C { p = 1; m() { } } +let c: C = new C() +let spreadC: { p: number } = { ...c } + +// own methods are enumerable +let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; +cplus.plus(); + +// new field's type conflicting with existing field is OK +let changeTypeAfter: { a: string, b: string } = + { ...o, a: 'wrong type?' } +let changeTypeBefore: { a: number, b: string } = + { a: 'wrong type?', ...o }; +let changeTypeBoth: { a: string, b: number } = + { ...o, ...swap }; + +// optional +let definiteBoolean: { sn: boolean }; +let definiteString: { sn: string }; +let optionalString: { sn?: string }; +let optionalNumber: { sn?: number }; +let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; + +// computed property +let computedFirst: { a: number, b: string, "before everything": number } = + { ['before everything']: 12, ...o, b: 'yes' } +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } +let computedAfter: { a: number, b: string, "at the end": number } = + { ...o, b: 'yeah', ['at the end']: 14 } +// shortcut syntax +let a = 12; +let shortCutted: { a: number, b: string } = { ...o, a } + +// generics +function f(t: T, u: U): { id: string, ...T, ...U } { + return { id: 'id', ...t, ...u }; +} +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) +let overwriteId: { id: boolean, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) + +class D { m() { }; q = 2; } +let classesAreWrong: { id: string, ...C, ...D } = + f(new C(), new D()) + + +//// [objectSpread.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var o = { a: 1, b: 'no' }; +var o2 = { b: 'yes', c: true }; +var swap = { a: 'yes', b: -1 }; +var addAfter = __assign({}, o, { c: false }); +var addBefore = __assign({ c: false }, o); +// Note: ignore still changes the order that properties are printed +var ignore = __assign({ b: 'ignored' }, o); +var override = __assign({}, o, { b: 'override' }); +var nested = __assign({}, __assign({ a: 3 }, { b: false, c: 'overriden' }), { c: 'whatever' }); +var combined = __assign({}, o, o2); +var combinedBefore = __assign({ b: 'ok' }, o, o2); +var combinedMid = __assign({}, o, { b: 'ok' }, o2); +var combinedAfter = __assign({}, o, o2, { b: 'ok' }); +var combinedNested = __assign({}, __assign({ a: 4 }, { b: false, c: 'overriden' }), { d: 'actually new' }, { a: 5, d: 'maybe new' }); +var combinedNestedChangeType = __assign({}, __assign({ a: 1 }, { b: false, c: 'overriden' }), { c: -1 }); +var propertyNested = __assign({ a: __assign({}, o) }); +// accessors don't copy the descriptor +// (which means that readonly getters become read/write properties) +var op = { get a() { return 6; } }; +var getter = __assign({}, op, { c: 7 }); +getter.a = 12; +// null and undefined are just skipped +var spreadNull = __assign({ a: 7 }, null); +var spreadUndefined = __assign({ a: 7 }, undefined); +// methods are not enumerable +var C = (function () { + function C() { + this.p = 1; + } + C.prototype.m = function () { }; + return C; +}()); +var c = new C(); +var spreadC = __assign({}, c); +// own methods are enumerable +var cplus = __assign({}, c, { plus: function () { return this.p + 1; } }); +cplus.plus(); +// new field's type conflicting with existing field is OK +var changeTypeAfter = __assign({}, o, { a: 'wrong type?' }); +var changeTypeBefore = __assign({ a: 'wrong type?' }, o); +var changeTypeBoth = __assign({}, o, swap); +// optional +var definiteBoolean; +var definiteString; +var optionalString; +var optionalNumber; +var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber); +var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber); +var allOptional = __assign({}, optionalString, optionalNumber); +// computed property +var computedFirst = __assign((_a = {}, _a['before everything'] = 12, _a), o, { b: 'yes' }); +var computedMiddle = __assign({}, o, (_b = {}, _b['in the middle'] = 13, _b.b = 'maybe?', _b), o2); +var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, _c)); +// shortcut syntax +var a = 12; +var shortCutted = __assign({}, o, { a: a }); +// generics +function f(t, u) { + return __assign({ id: 'id' }, t, u); +} +var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false }); +var overlap = f({ a: 1 }, { a: 2, b: 'extra' }); +var overlapConflict = f({ a: 1 }, { a: 'mismatch' }); +var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' }); +var D = (function () { + function D() { + this.q = 2; + } + D.prototype.m = function () { }; + ; + return D; +}()); +var classesAreWrong = f(new C(), new D()); +var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols new file mode 100644 index 0000000000000..001c42804d2b4 --- /dev/null +++ b/tests/baselines/reference/objectSpread.symbols @@ -0,0 +1,369 @@ +=== tests/cases/conformance/types/spread/objectSpread.ts === +let o = { a: 1, b: 'no' } +>o : Symbol(o, Decl(objectSpread.ts, 0, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 0, 9)) +>b : Symbol(b, Decl(objectSpread.ts, 0, 15)) + +let o2 = { b: 'yes', c: true } +>o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3)) +>b : Symbol(b, Decl(objectSpread.ts, 1, 10)) +>c : Symbol(c, Decl(objectSpread.ts, 1, 20)) + +let swap = { a: 'yes', b: -1 }; +>swap : Symbol(swap, Decl(objectSpread.ts, 2, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 2, 12)) +>b : Symbol(b, Decl(objectSpread.ts, 2, 22)) + +let addAfter: { a: number, b: string, c: boolean } = +>addAfter : Symbol(addAfter, Decl(objectSpread.ts, 4, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 4, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 4, 26)) +>c : Symbol(c, Decl(objectSpread.ts, 4, 37)) + + { ...o, c: false } +>c : Symbol(c, Decl(objectSpread.ts, 5, 11)) + +let addBefore: { a: number, b: string, c: boolean } = +>addBefore : Symbol(addBefore, Decl(objectSpread.ts, 6, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 6, 16)) +>b : Symbol(b, Decl(objectSpread.ts, 6, 27)) +>c : Symbol(c, Decl(objectSpread.ts, 6, 38)) + + { c: false, ...o } +>c : Symbol(c, Decl(objectSpread.ts, 7, 5)) + +// Note: ignore still changes the order that properties are printed +let ignore: { a: number, b: string } = +>ignore : Symbol(ignore, Decl(objectSpread.ts, 9, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 9, 13)) +>b : Symbol(b, Decl(objectSpread.ts, 9, 24)) + + { b: 'ignored', ...o } +>b : Symbol(b, Decl(objectSpread.ts, 10, 5)) + +let override: { a: number, b: string } = +>override : Symbol(override, Decl(objectSpread.ts, 11, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 11, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 11, 26)) + + { ...o, b: 'override' } +>b : Symbol(b, Decl(objectSpread.ts, 12, 11)) + +let nested: { a: number, b: boolean, c: string } = +>nested : Symbol(nested, Decl(objectSpread.ts, 13, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 13, 13)) +>b : Symbol(b, Decl(objectSpread.ts, 13, 24)) +>c : Symbol(c, Decl(objectSpread.ts, 13, 36)) + + { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } +>a : Symbol(a, Decl(objectSpread.ts, 14, 10)) +>b : Symbol(b, Decl(objectSpread.ts, 14, 21)) +>c : Symbol(c, Decl(objectSpread.ts, 14, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 14, 51)) + +let combined: { a: number, b: string, c: boolean } = +>combined : Symbol(combined, Decl(objectSpread.ts, 15, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 15, 15)) +>b : Symbol(b, Decl(objectSpread.ts, 15, 26)) +>c : Symbol(c, Decl(objectSpread.ts, 15, 37)) + + { ...o, ...o2 } +let combinedBefore: { a: number, b: string, c: boolean } = +>combinedBefore : Symbol(combinedBefore, Decl(objectSpread.ts, 17, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 17, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 17, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 17, 43)) + + { b: 'ok', ...o, ...o2 } +>b : Symbol(b, Decl(objectSpread.ts, 18, 5)) + +let combinedMid: { a: number, b: string, c: boolean } = +>combinedMid : Symbol(combinedMid, Decl(objectSpread.ts, 19, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 19, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 19, 29)) +>c : Symbol(c, Decl(objectSpread.ts, 19, 40)) + + { ...o, b: 'ok', ...o2 } +>b : Symbol(b, Decl(objectSpread.ts, 20, 11)) + +let combinedAfter: { a: number, b: string, c: boolean } = +>combinedAfter : Symbol(combinedAfter, Decl(objectSpread.ts, 21, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 21, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 21, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 21, 42)) + + { ...o, ...o2, b: 'ok' } +>b : Symbol(b, Decl(objectSpread.ts, 22, 18)) + +let combinedNested: { a: number, b: boolean, c: string, d: string } = +>combinedNested : Symbol(combinedNested, Decl(objectSpread.ts, 23, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 23, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 23, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 23, 44)) +>d : Symbol(d, Decl(objectSpread.ts, 23, 55)) + + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +>a : Symbol(a, Decl(objectSpread.ts, 24, 10)) +>b : Symbol(b, Decl(objectSpread.ts, 24, 21)) +>c : Symbol(c, Decl(objectSpread.ts, 24, 31)) +>d : Symbol(d, Decl(objectSpread.ts, 24, 51)) +>a : Symbol(a, Decl(objectSpread.ts, 24, 75)) +>d : Symbol(d, Decl(objectSpread.ts, 24, 81)) + +let combinedNestedChangeType: { a: number, b: boolean, c: number } = +>combinedNestedChangeType : Symbol(combinedNestedChangeType, Decl(objectSpread.ts, 25, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 25, 31)) +>b : Symbol(b, Decl(objectSpread.ts, 25, 42)) +>c : Symbol(c, Decl(objectSpread.ts, 25, 54)) + + { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } +>a : Symbol(a, Decl(objectSpread.ts, 26, 10)) +>b : Symbol(b, Decl(objectSpread.ts, 26, 21)) +>c : Symbol(c, Decl(objectSpread.ts, 26, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 26, 51)) + +let propertyNested: { a: { a: number, b: string } } = +>propertyNested : Symbol(propertyNested, Decl(objectSpread.ts, 27, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 27, 21)) +>a : Symbol(a, Decl(objectSpread.ts, 27, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 27, 37)) + + { a: { ... o } } +>a : Symbol(a, Decl(objectSpread.ts, 28, 5)) + +// accessors don't copy the descriptor +// (which means that readonly getters become read/write properties) +let op = { get a () { return 6 } }; +>op : Symbol(op, Decl(objectSpread.ts, 31, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 31, 10)) + +let getter: { a: number, c: number } = +>getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 32, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 32, 24)) + + { ...op, c: 7 } +>c : Symbol(c, Decl(objectSpread.ts, 33, 12)) + +getter.a = 12; +>getter.a : Symbol(a, Decl(objectSpread.ts, 32, 13)) +>getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 32, 13)) + +// null and undefined are just skipped +let spreadNull: { a: number } = +>spreadNull : Symbol(spreadNull, Decl(objectSpread.ts, 37, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 37, 17)) + + { a: 7, ...null } +>a : Symbol(a, Decl(objectSpread.ts, 38, 5)) + +let spreadUndefined: { a: number } = +>spreadUndefined : Symbol(spreadUndefined, Decl(objectSpread.ts, 39, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 39, 22)) + + { a: 7, ...undefined } +>a : Symbol(a, Decl(objectSpread.ts, 40, 5)) + +// methods are not enumerable +class C { p = 1; m() { } } +>C : Symbol(C, Decl(objectSpread.ts, 40, 26)) +>p : Symbol(C.p, Decl(objectSpread.ts, 43, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 43, 16)) + +let c: C = new C() +>c : Symbol(c, Decl(objectSpread.ts, 44, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 40, 26)) +>C : Symbol(C, Decl(objectSpread.ts, 40, 26)) + +let spreadC: { p: number } = { ...c } +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 45, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 45, 14)) + +// own methods are enumerable +let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; +>cplus : Symbol(cplus, Decl(objectSpread.ts, 48, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 48, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 48, 23)) +>plus : Symbol(plus, Decl(objectSpread.ts, 48, 48)) + +cplus.plus(); +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 48, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 48, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 48, 23)) + +// new field's type conflicting with existing field is OK +let changeTypeAfter: { a: string, b: string } = +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 52, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 52, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 52, 33)) + + { ...o, a: 'wrong type?' } +>a : Symbol(a, Decl(objectSpread.ts, 53, 11)) + +let changeTypeBefore: { a: number, b: string } = +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 54, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 54, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 54, 34)) + + { a: 'wrong type?', ...o }; +>a : Symbol(a, Decl(objectSpread.ts, 55, 5)) + +let changeTypeBoth: { a: string, b: number } = +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 56, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 56, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 56, 32)) + + { ...o, ...swap }; + +// optional +let definiteBoolean: { sn: boolean }; +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 60, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 60, 22)) + +let definiteString: { sn: string }; +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 61, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 61, 21)) + +let optionalString: { sn?: string }; +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 62, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 62, 21)) + +let optionalNumber: { sn?: number }; +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 63, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) + +let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 64, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 64, 25)) + +let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 65, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 65, 30)) + +let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 66, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 66, 18)) + +// computed property +let computedFirst: { a: number, b: string, "before everything": number } = +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 69, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 69, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 69, 31)) + + { ['before everything']: 12, ...o, b: 'yes' } +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 70, 5)) +>b : Symbol(b, Decl(objectSpread.ts, 70, 38)) + +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 71, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 71, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 71, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 71, 43)) + + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 72, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 72, 34)) + +let computedAfter: { a: number, b: string, "at the end": number } = +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 73, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 73, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 73, 31)) + + { ...o, b: 'yeah', ['at the end']: 14 } +>b : Symbol(b, Decl(objectSpread.ts, 74, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 74, 22)) + +// shortcut syntax +let a = 12; +>a : Symbol(a, Decl(objectSpread.ts, 76, 3)) + +let shortCutted: { a: number, b: string } = { ...o, a } +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 77, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 77, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 77, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 77, 51)) + +// generics +function f(t: T, u: U): { id: string, ...T, ...U } { +>f : Symbol(f, Decl(objectSpread.ts, 77, 55)) +>T : Symbol(T, Decl(objectSpread.ts, 80, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 80, 13)) +>t : Symbol(t, Decl(objectSpread.ts, 80, 17)) +>T : Symbol(T, Decl(objectSpread.ts, 80, 11)) +>u : Symbol(u, Decl(objectSpread.ts, 80, 22)) +>U : Symbol(U, Decl(objectSpread.ts, 80, 13)) +>id : Symbol(id, Decl(objectSpread.ts, 80, 31)) +>T : Symbol(T, Decl(objectSpread.ts, 80, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 80, 13)) + + return { id: 'id', ...t, ...u }; +>id : Symbol(id, Decl(objectSpread.ts, 81, 12)) +} +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = +>exclusive : Symbol(exclusive, Decl(objectSpread.ts, 83, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 83, 16)) +>a : Symbol(a, Decl(objectSpread.ts, 83, 28)) +>b : Symbol(b, Decl(objectSpread.ts, 83, 39)) +>c : Symbol(c, Decl(objectSpread.ts, 83, 50)) +>d : Symbol(d, Decl(objectSpread.ts, 83, 61)) + + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +>f : Symbol(f, Decl(objectSpread.ts, 77, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 84, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 84, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 84, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 84, 36)) + +let overlap: { id: string, a: number, b: string } = +>overlap : Symbol(overlap, Decl(objectSpread.ts, 85, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 85, 14)) +>a : Symbol(a, Decl(objectSpread.ts, 85, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 85, 37)) + + f({ a: 1 }, { a: 2, b: 'extra' }) +>f : Symbol(f, Decl(objectSpread.ts, 77, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 86, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 86, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 86, 23)) + +let overlapConflict: { id:string, a: string } = +>overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 87, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 87, 22)) +>a : Symbol(a, Decl(objectSpread.ts, 87, 33)) + + f({ a: 1 }, { a: 'mismatch' }) +>f : Symbol(f, Decl(objectSpread.ts, 77, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 17)) + +let overwriteId: { id: boolean, a: number, c: number, d: string } = +>overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 89, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 89, 18)) +>a : Symbol(a, Decl(objectSpread.ts, 89, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 89, 42)) +>d : Symbol(d, Decl(objectSpread.ts, 89, 53)) + + f({ a: 1, id: true }, { c: 1, d: 'no' }) +>f : Symbol(f, Decl(objectSpread.ts, 77, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 7)) +>id : Symbol(id, Decl(objectSpread.ts, 90, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 90, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 90, 33)) + +class D { m() { }; q = 2; } +>D : Symbol(D, Decl(objectSpread.ts, 90, 44)) +>m : Symbol(D.m, Decl(objectSpread.ts, 92, 9)) +>q : Symbol(D.q, Decl(objectSpread.ts, 92, 18)) + +let classesAreWrong: { id: string, ...C, ...D } = +>classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 93, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 93, 22)) +>C : Symbol(C, Decl(objectSpread.ts, 40, 26)) +>D : Symbol(D, Decl(objectSpread.ts, 90, 44)) + + f(new C(), new D()) +>f : Symbol(f, Decl(objectSpread.ts, 77, 55)) +>C : Symbol(C, Decl(objectSpread.ts, 40, 26)) +>D : Symbol(D, Decl(objectSpread.ts, 90, 44)) + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types new file mode 100644 index 0000000000000..1a053a22670c0 --- /dev/null +++ b/tests/baselines/reference/objectSpread.types @@ -0,0 +1,530 @@ +=== tests/cases/conformance/types/spread/objectSpread.ts === +let o = { a: 1, b: 'no' } +>o : { a: number; b: string; } +>{ a: 1, b: 'no' } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>'no' : "no" + +let o2 = { b: 'yes', c: true } +>o2 : { b: string; c: boolean; } +>{ b: 'yes', c: true } : { b: string; c: boolean; } +>b : string +>'yes' : "yes" +>c : boolean +>true : true + +let swap = { a: 'yes', b: -1 }; +>swap : { a: string; b: number; } +>{ a: 'yes', b: -1 } : { a: string; b: number; } +>a : string +>'yes' : "yes" +>b : number +>-1 : -1 +>1 : 1 + +let addAfter: { a: number, b: string, c: boolean } = +>addAfter : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { ...o, c: false } +>{ ...o, c: false } : { ...{ a: number; b: string; }; c: false; } +>o : any +>c : boolean +>false : false + +let addBefore: { a: number, b: string, c: boolean } = +>addBefore : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { c: false, ...o } +>{ c: false, ...o } : { c: false; ...{ a: number; b: string; } } +>c : boolean +>false : false +>o : any + +// Note: ignore still changes the order that properties are printed +let ignore: { a: number, b: string } = +>ignore : { a: number; b: string; } +>a : number +>b : string + + { b: 'ignored', ...o } +>{ b: 'ignored', ...o } : { b: string; ...{ a: number; b: string; } } +>b : string +>'ignored' : "ignored" +>o : any + +let override: { a: number, b: string } = +>override : { a: number; b: string; } +>a : number +>b : string + + { ...o, b: 'override' } +>{ ...o, b: 'override' } : { ...{ a: number; b: string; }; b: string; } +>o : any +>b : string +>'override' : "override" + +let nested: { a: number, b: boolean, c: string } = +>nested : { a: number; b: boolean; c: string; } +>a : number +>b : boolean +>c : string + + { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } +>{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } : { ...{ a: number; ...{ b: boolean; c: string; } }; c: string; } +>{ a: 3, ...{ b: false, c: 'overriden' } } : { a: number; ...{ b: boolean; c: string; } } +>a : number +>3 : 3 +>{ b: false, c: 'overriden' } : { b: boolean; c: string; } +>b : boolean +>false : false +>c : string +>'overriden' : "overriden" +>c : string +>'whatever' : "whatever" + +let combined: { a: number, b: string, c: boolean } = +>combined : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { ...o, ...o2 } +>{ ...o, ...o2 } : { ...{ a: number; b: string; }; ...{ b: string; c: boolean; } } +>o : any +>o2 : any + +let combinedBefore: { a: number, b: string, c: boolean } = +>combinedBefore : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { b: 'ok', ...o, ...o2 } +>{ b: 'ok', ...o, ...o2 } : { b: string; ...{ a: number; b: string; }; ...{ b: string; c: boolean; } } +>b : string +>'ok' : "ok" +>o : any +>o2 : any + +let combinedMid: { a: number, b: string, c: boolean } = +>combinedMid : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { ...o, b: 'ok', ...o2 } +>{ ...o, b: 'ok', ...o2 } : { ...{ a: number; b: string; }; b: string; ...{ b: string; c: boolean; } } +>o : any +>b : string +>'ok' : "ok" +>o2 : any + +let combinedAfter: { a: number, b: string, c: boolean } = +>combinedAfter : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + + { ...o, ...o2, b: 'ok' } +>{ ...o, ...o2, b: 'ok' } : { ...{ a: number; b: string; }; ...{ b: string; c: boolean; }; b: string; } +>o : any +>o2 : any +>b : string +>'ok' : "ok" + +let combinedNested: { a: number, b: boolean, c: string, d: string } = +>combinedNested : { a: number; b: boolean; c: string; d: string; } +>a : number +>b : boolean +>c : string +>d : string + + { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } +>{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } : { ...{ a: number; ...{ b: boolean; c: string; } }; d: string; ...{ a: number; d: string; } } +>{ a: 4, ...{ b: false, c: 'overriden' } } : { a: number; ...{ b: boolean; c: string; } } +>a : number +>4 : 4 +>{ b: false, c: 'overriden' } : { b: boolean; c: string; } +>b : boolean +>false : false +>c : string +>'overriden' : "overriden" +>d : string +>'actually new' : "actually new" +>{ a: 5, d: 'maybe new' } : { a: number; d: string; } +>a : number +>5 : 5 +>d : string +>'maybe new' : "maybe new" + +let combinedNestedChangeType: { a: number, b: boolean, c: number } = +>combinedNestedChangeType : { a: number; b: boolean; c: number; } +>a : number +>b : boolean +>c : number + + { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } +>{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } : { ...{ a: number; ...{ b: boolean; c: string; } }; c: number; } +>{ a: 1, ...{ b: false, c: 'overriden' } } : { a: number; ...{ b: boolean; c: string; } } +>a : number +>1 : 1 +>{ b: false, c: 'overriden' } : { b: boolean; c: string; } +>b : boolean +>false : false +>c : string +>'overriden' : "overriden" +>c : number +>-1 : -1 +>1 : 1 + +let propertyNested: { a: { a: number, b: string } } = +>propertyNested : { a: { a: number; b: string; }; } +>a : { a: number; b: string; } +>a : number +>b : string + + { a: { ... o } } +>{ a: { ... o } } : { a: { ...{ a: number; b: string; } }; } +>a : { ...{ a: number; b: string; } } +>{ ... o } : { ...{ a: number; b: string; } } +>o : any + +// accessors don't copy the descriptor +// (which means that readonly getters become read/write properties) +let op = { get a () { return 6 } }; +>op : { readonly a: number; } +>{ get a () { return 6 } } : { readonly a: number; } +>a : number +>6 : 6 + +let getter: { a: number, c: number } = +>getter : { a: number; c: number; } +>a : number +>c : number + + { ...op, c: 7 } +>{ ...op, c: 7 } : { ...{ readonly a: number; }; c: number; } +>op : any +>c : number +>7 : 7 + +getter.a = 12; +>getter.a = 12 : 12 +>getter.a : number +>getter : { a: number; c: number; } +>a : number +>12 : 12 + +// null and undefined are just skipped +let spreadNull: { a: number } = +>spreadNull : { a: number; } +>a : number + + { a: 7, ...null } +>{ a: 7, ...null } : { a: number; } +>a : number +>7 : 7 +>null : null + +let spreadUndefined: { a: number } = +>spreadUndefined : { a: number; } +>a : number + + { a: 7, ...undefined } +>{ a: 7, ...undefined } : { a: number; } +>a : number +>7 : 7 +>undefined : any + +// methods are not enumerable +class C { p = 1; m() { } } +>C : C +>p : number +>1 : 1 +>m : () => void + +let c: C = new C() +>c : C +>C : C +>new C() : C +>C : typeof C + +let spreadC: { p: number } = { ...c } +>spreadC : { p: number; } +>p : number +>{ ...c } : { ...C } +>c : any + +// own methods are enumerable +let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; +>cplus : { p: number; plus(): void; } +>p : number +>plus : () => void +>{ ...c, plus() { return this.p + 1; } } : { ...C; plus(): any; } +>c : any +>plus : () => any +>this.p + 1 : any +>this.p : any +>this : any +>p : any +>1 : 1 + +cplus.plus(); +>cplus.plus() : void +>cplus.plus : () => void +>cplus : { p: number; plus(): void; } +>plus : () => void + +// new field's type conflicting with existing field is OK +let changeTypeAfter: { a: string, b: string } = +>changeTypeAfter : { a: string; b: string; } +>a : string +>b : string + + { ...o, a: 'wrong type?' } +>{ ...o, a: 'wrong type?' } : { ...{ a: number; b: string; }; a: string; } +>o : any +>a : string +>'wrong type?' : "wrong type?" + +let changeTypeBefore: { a: number, b: string } = +>changeTypeBefore : { a: number; b: string; } +>a : number +>b : string + + { a: 'wrong type?', ...o }; +>{ a: 'wrong type?', ...o } : { a: string; ...{ a: number; b: string; } } +>a : string +>'wrong type?' : "wrong type?" +>o : any + +let changeTypeBoth: { a: string, b: number } = +>changeTypeBoth : { a: string; b: number; } +>a : string +>b : number + + { ...o, ...swap }; +>{ ...o, ...swap } : { ...{ a: number; b: string; }; ...{ a: string; b: number; } } +>o : any +>swap : any + +// optional +let definiteBoolean: { sn: boolean }; +>definiteBoolean : { sn: boolean; } +>sn : boolean + +let definiteString: { sn: string }; +>definiteString : { sn: string; } +>sn : string + +let optionalString: { sn?: string }; +>optionalString : { sn?: string; } +>sn : string + +let optionalNumber: { sn?: number }; +>optionalNumber : { sn?: number; } +>sn : number + +let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +>optionalUnionStops : { sn: string | number | boolean; } +>sn : string | number | boolean +>{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { ...{ sn: boolean; }; ...{ sn: string; }; ...{ sn?: number; } } +>definiteBoolean : any +>definiteString : any +>optionalNumber : any + +let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +>optionalUnionDuplicates : { sn: string | number; } +>sn : string | number +>{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { ...{ sn: boolean; }; ...{ sn: string; }; ...{ sn?: string; }; ...{ sn?: number; } } +>definiteBoolean : any +>definiteString : any +>optionalString : any +>optionalNumber : any + +let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +>allOptional : { sn?: string | number; } +>sn : string | number +>{ ...optionalString, ...optionalNumber } : { ...{ sn?: string; }; ...{ sn?: number; } } +>optionalString : any +>optionalNumber : any + +// computed property +let computedFirst: { a: number, b: string, "before everything": number } = +>computedFirst : { a: number; b: string; "before everything": number; } +>a : number +>b : string + + { ['before everything']: 12, ...o, b: 'yes' } +>{ ['before everything']: 12, ...o, b: 'yes' } : { ['before everything']: number; ...{ a: number; b: string; }; b: string; } +>'before everything' : "before everything" +>12 : 12 +>o : any +>b : string +>'yes' : "yes" + +let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = +>computedMiddle : { a: number; b: string; c: boolean; "in the middle": number; } +>a : number +>b : string +>c : boolean + + { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } +>{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { ...{ a: number; b: string; }; ['in the middle']: number; b: string; ...{ b: string; c: boolean; } } +>o : any +>'in the middle' : "in the middle" +>13 : 13 +>b : string +>'maybe?' : "maybe?" +>o2 : any + +let computedAfter: { a: number, b: string, "at the end": number } = +>computedAfter : { a: number; b: string; "at the end": number; } +>a : number +>b : string + + { ...o, b: 'yeah', ['at the end']: 14 } +>{ ...o, b: 'yeah', ['at the end']: 14 } : { ...{ a: number; b: string; }; b: string; ['at the end']: number; } +>o : any +>b : string +>'yeah' : "yeah" +>'at the end' : "at the end" +>14 : 14 + +// shortcut syntax +let a = 12; +>a : number +>12 : 12 + +let shortCutted: { a: number, b: string } = { ...o, a } +>shortCutted : { a: number; b: string; } +>a : number +>b : string +>{ ...o, a } : { ...{ a: number; b: string; }; a: number; } +>o : any +>a : number + +// generics +function f(t: T, u: U): { id: string, ...T, ...U } { +>f : (t: T, u: U) => { id: string; ...T; ...U } +>T : T +>U : U +>t : T +>T : T +>u : U +>U : U +>id : string +>T : T +>U : U + + return { id: 'id', ...t, ...u }; +>{ id: 'id', ...t, ...u } : { id: string; ...T; ...U } +>id : string +>'id' : "id" +>t : any +>u : any +} +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = +>exclusive : { id: string; a: number; b: string; c: string; d: boolean; } +>id : string +>a : number +>b : string +>c : string +>d : boolean + + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { id: string; ...{ a: number; b: string; }; ...{ c: string; d: boolean; } } +>f : (t: T, u: U) => { id: string; ...T; ...U } +>{ a: 1, b: 'yes' } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>'yes' : "yes" +>{ c: 'no', d: false } : { c: string; d: false; } +>c : string +>'no' : "no" +>d : boolean +>false : false + +let overlap: { id: string, a: number, b: string } = +>overlap : { id: string; a: number; b: string; } +>id : string +>a : number +>b : string + + f({ a: 1 }, { a: 2, b: 'extra' }) +>f({ a: 1 }, { a: 2, b: 'extra' }) : { id: string; ...{ a: number; }; ...{ a: number; b: string; } } +>f : (t: T, u: U) => { id: string; ...T; ...U } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 +>{ a: 2, b: 'extra' } : { a: number; b: string; } +>a : number +>2 : 2 +>b : string +>'extra' : "extra" + +let overlapConflict: { id:string, a: string } = +>overlapConflict : { id: string; a: string; } +>id : string +>a : string + + f({ a: 1 }, { a: 'mismatch' }) +>f({ a: 1 }, { a: 'mismatch' }) : { id: string; ...{ a: number; }; ...{ a: string; } } +>f : (t: T, u: U) => { id: string; ...T; ...U } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 +>{ a: 'mismatch' } : { a: string; } +>a : string +>'mismatch' : "mismatch" + +let overwriteId: { id: boolean, a: number, c: number, d: string } = +>overwriteId : { id: boolean; a: number; c: number; d: string; } +>id : boolean +>a : number +>c : number +>d : string + + f({ a: 1, id: true }, { c: 1, d: 'no' }) +>f({ a: 1, id: true }, { c: 1, d: 'no' }) : { id: string; ...{ a: number; id: boolean; }; ...{ c: number; d: string; } } +>f : (t: T, u: U) => { id: string; ...T; ...U } +>{ a: 1, id: true } : { a: number; id: true; } +>a : number +>1 : 1 +>id : boolean +>true : true +>{ c: 1, d: 'no' } : { c: number; d: string; } +>c : number +>1 : 1 +>d : string +>'no' : "no" + +class D { m() { }; q = 2; } +>D : D +>m : () => void +>q : number +>2 : 2 + +let classesAreWrong: { id: string, ...C, ...D } = +>classesAreWrong : { id: string; ...C; ...D } +>id : string +>C : C +>D : D + + f(new C(), new D()) +>f(new C(), new D()) : { id: string; ...C; ...D } +>f : (t: T, u: U) => { id: string; ...T; ...U } +>new C() : C +>C : typeof C +>new D() : D +>D : typeof D + diff --git a/tests/baselines/reference/objectSpreadGeneric.errors.txt b/tests/baselines/reference/objectSpreadGeneric.errors.txt new file mode 100644 index 0000000000000..16dfc835d2607 --- /dev/null +++ b/tests/baselines/reference/objectSpreadGeneric.errors.txt @@ -0,0 +1,80 @@ +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(4,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(5,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...T; ...V }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(6,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(7,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(8,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(13,11): error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(26,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(34,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + Property 'first' is missing in type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(36,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + Property 'second' is missing in type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + Property 'third' is missing in type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }'. + + +==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (10 errors) ==== + function f(t: T, u: U, v: V): void { + let o: { ...T, ...U, ...V }; + const same: { ...T, ...U, ...V } = o; // ok + const reversed: { ...V, ...U, ...T } = o; // error, reversed + ~~~~~~~~ +!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. + const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed + ~~~~~~~~~ +!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...T; ...V }'. + const missingT: { ...U, ...V } = o; // error, missing T + ~~~~~~~~ +!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. + const missingU: { ...T, ...V } = o; // error, missing U + ~~~~~~~~ +!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. + const missingV: { ...T, ...U } = o; // error, missing V + ~~~~~~~~ +!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. + const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok + const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // ok + + const emptyTarget: { } = { ...t, ...u } // ok + const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) + ~~~~~~~~~~~ +!!! error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. + + let optionalNumber: { sn?: number }; + let optionalString: { sn?: string }; + let optionalBoolean: { sn?: boolean }; + const unionCutoff: { ...T, sn?: number | string | boolean } = + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } // ok + unionCutoff.sn; // ok + const optionalCutoff = { ...t, ...optionalNumber }; // ok + optionalCutoff.sn; // ok + + const interspersed: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, second: '2', ...u, third: '3' }; // ok + const interspersedMissingU: { first: string, second: string, ...T, third: string } = + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing + const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + + + const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +!!! error TS2322: Property 'first' is missing in type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }'. + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found + const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = + ~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +!!! error TS2322: Property 'second' is missing in type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }'. + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found + const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = + ~~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +!!! error TS2322: Property 'third' is missing in type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }'. + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found + } + \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadGeneric.js b/tests/baselines/reference/objectSpreadGeneric.js new file mode 100644 index 0000000000000..593ab73f98fac --- /dev/null +++ b/tests/baselines/reference/objectSpreadGeneric.js @@ -0,0 +1,79 @@ +//// [objectSpreadGeneric.ts] +function f(t: T, u: U, v: V): void { + let o: { ...T, ...U, ...V }; + const same: { ...T, ...U, ...V } = o; // ok + const reversed: { ...V, ...U, ...T } = o; // error, reversed + const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed + const missingT: { ...U, ...V } = o; // error, missing T + const missingU: { ...T, ...V } = o; // error, missing U + const missingV: { ...T, ...U } = o; // error, missing V + const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok + const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // ok + + const emptyTarget: { } = { ...t, ...u } // ok + const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) + + let optionalNumber: { sn?: number }; + let optionalString: { sn?: string }; + let optionalBoolean: { sn?: boolean }; + const unionCutoff: { ...T, sn?: number | string | boolean } = + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } // ok + unionCutoff.sn; // ok + const optionalCutoff = { ...t, ...optionalNumber }; // ok + optionalCutoff.sn; // ok + + const interspersed: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, second: '2', ...u, third: '3' }; // ok + const interspersedMissingU: { first: string, second: string, ...T, third: string } = + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing + const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + + + const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found + const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found + const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found +} + + +//// [objectSpreadGeneric.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +function f(t, u, v) { + var o; + var same = o; // ok + var reversed = o; // error, reversed + var reversed2 = o; // error, U and T are still reversed + var missingT = o; // error, missing T + var missingU = o; // error, missing U + var missingV = o; // error, missing V + var atEnd = __assign({}, t, u, { second: 'foo' }); // ok + var atBeginning = __assign({ first: 'foo' }, t, u); // ok + var emptyTarget = __assign({}, t, u); // ok + var emptySource = {}; // error, {} is not assignable to U (or T) + var optionalNumber; + var optionalString; + var optionalBoolean; + var unionCutoff = __assign({}, optionalBoolean, t, optionalString, optionalNumber); // ok + unionCutoff.sn; // ok + var optionalCutoff = __assign({}, t, optionalNumber); // ok + optionalCutoff.sn; // ok + var interspersed = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // ok + var interspersedMissingU = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, 'U' is missing + var interspersedOrder1 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // ok + var interspersedOrder2 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // ok + var mismatchFirst = __assign({ firrrrrrst: '1' }, t, { second: '2' }, u, { third: '3' }); // error, 'first' not found + var mismatchSecond = __assign({ first: '1' }, t, { ssssssssecond: '2' }, u, { third: '3' }); // error, 'second' not found + var mismatchLast = __assign({ first: '1' }, t, { second: '2' }, u, { thirrrrrrrd: '3' }); // error, 'third' not found +} diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt new file mode 100644 index 0000000000000..1ee3acb823c6a --- /dev/null +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -0,0 +1,93 @@ +tests/cases/conformance/types/spread/objectSpreadNegative.ts(13,30): error TS2339: Property 'x' does not exist on type '{ ...PublicX; ...PrivateOptionalX }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(16,5): error TS2322: Type '{ ...{ sn?: string; }; ...{ sn?: number; } }' is not assignable to type '{ sn: string | number; }'. + Property 'sn' is optional in type '{ ...{ sn?: string; }; ...{ sn?: number; } }' but required in type '{ sn: string | number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(22,5): error TS2322: Type '{ s: string; }' is not assignable to type '{ ...Bool; ...Str }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(24,1): error TS2322: Type 'Bool' is not assignable to type '{ ...Bool; ...Str }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(31,36): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(31,53): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,12): error TS2339: Property 'b' does not exist on type '{ ...{ b: number; } }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,9): error TS2339: Property 'm' does not exist on type '{ ...C }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ ...PublicX }' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,39): error TS2697: Spread properties must be identifiers, property accesses, or object literals. + + +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (13 errors) ==== + let o = { a: 1, b: 'no' } + + /// private propagates + class PrivateOptionalX { + private x?: number; + } + class PublicX { + public x: number; + } + let privateOptionalx: PrivateOptionalX; + let publicx: PublicX; + let o3 = { ...publicx, ...privateOptionalx }; + let sn: string | number = o3.x; // error, x is private + ~ +!!! error TS2339: Property 'x' does not exist on type '{ ...PublicX; ...PrivateOptionalX }'. + let optionalString: { sn?: string }; + let optionalNumber: { sn?: number }; + let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; + ~~~~~~~~~~~ +!!! error TS2322: Type '{ ...{ sn?: string; }; ...{ sn?: number; } }' is not assignable to type '{ sn: string | number; }'. +!!! error TS2322: Property 'sn' is optional in type '{ ...{ sn?: string; }; ...{ sn?: number; } }' but required in type '{ sn: string | number; }'. + // error, 'sn' is optional in source, required in target + + // assignability as target + interface Bool { b: boolean }; + interface Str { s: string }; + let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' + ~~~~~~ +!!! error TS2322: Type '{ s: string; }' is not assignable to type '{ ...Bool; ...Str }'. + let b: Bool; + spread = b; // error, missing 's' + ~~~~~~ +!!! error TS2322: Type 'Bool' is not assignable to type '{ ...Bool; ...Str }'. + + // expressions are not allowed + let o1 = { ...1 + 1 }; + ~~~~~ +!!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. + let o2 = { ...(1 + 1) }; + ~~~~~~~ +!!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. + + // literal repeats are not allowed, but spread repeats are fine + let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } + ~ +!!! error TS2300: Duplicate identifier 'b'. + ~ +!!! error TS2300: Duplicate identifier 'b'. + let duplicatedSpread = { ...o, ...o } + + // write-only properties get skipped + let setterOnly = { ...{ set b (bad: number) { } } }; + setterOnly.b = 12; // error, 'b' does not exist + ~ +!!! error TS2339: Property 'b' does not exist on type '{ ...{ b: number; } }'. + + // methods are skipped because they aren't enumerable + class C { p = 1; m() { } } + let c: C = new C() + let spreadC = { ...c } + spreadC.m(); // error 'm' is not in '{ ... c }' + ~ +!!! error TS2339: Property 'm' does not exist on type '{ ...C }'. + + let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; + callableConstructableSpread(12); // error, no call signature + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ ...PublicX }' has no compatible call signatures. + new callableConstructableSpread(12); // error, no construct signature + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. + + let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions + ~~~~~~~~~~~~ +!!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. + \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js new file mode 100644 index 0000000000000..685760f944467 --- /dev/null +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -0,0 +1,108 @@ +//// [objectSpreadNegative.ts] +let o = { a: 1, b: 'no' } + +/// private propagates +class PrivateOptionalX { + private x?: number; +} +class PublicX { + public x: number; +} +let privateOptionalx: PrivateOptionalX; +let publicx: PublicX; +let o3 = { ...publicx, ...privateOptionalx }; +let sn: string | number = o3.x; // error, x is private +let optionalString: { sn?: string }; +let optionalNumber: { sn?: number }; +let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; +// error, 'sn' is optional in source, required in target + +// assignability as target +interface Bool { b: boolean }; +interface Str { s: string }; +let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' +let b: Bool; +spread = b; // error, missing 's' + +// expressions are not allowed +let o1 = { ...1 + 1 }; +let o2 = { ...(1 + 1) }; + +// literal repeats are not allowed, but spread repeats are fine +let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } +let duplicatedSpread = { ...o, ...o } + +// write-only properties get skipped +let setterOnly = { ...{ set b (bad: number) { } } }; +setterOnly.b = 12; // error, 'b' does not exist + +// methods are skipped because they aren't enumerable +class C { p = 1; m() { } } +let c: C = new C() +let spreadC = { ...c } +spreadC.m(); // error 'm' is not in '{ ... c }' + +let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; +callableConstructableSpread(12); // error, no call signature +new callableConstructableSpread(12); // error, no construct signature + +let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions + + +//// [objectSpreadNegative.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var o = { a: 1, b: 'no' }; +/// private propagates +var PrivateOptionalX = (function () { + function PrivateOptionalX() { + } + return PrivateOptionalX; +}()); +var PublicX = (function () { + function PublicX() { + } + return PublicX; +}()); +var privateOptionalx; +var publicx; +var o3 = __assign({}, publicx, privateOptionalx); +var sn = o3.x; // error, x is private +var optionalString; +var optionalNumber; +var allOptional = __assign({}, optionalString, optionalNumber); +; +; +var spread = { s: 'foo' }; // error, missing 'b' +var b; +spread = b; // error, missing 's' +// expressions are not allowed +var o1 = __assign({}, 1 + 1); +var o2 = __assign({}, (1 + 1)); +// literal repeats are not allowed, but spread repeats are fine +var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); +var duplicatedSpread = __assign({}, o, o); +// write-only properties get skipped +var setterOnly = __assign({ set b(bad: number) { } }); +setterOnly.b = 12; // error, 'b' does not exist +// methods are skipped because they aren't enumerable +var C = (function () { + function C() { + this.p = 1; + } + C.prototype.m = function () { }; + return C; +}()); +var c = new C(); +var spreadC = __assign({}, c); +spreadC.m(); // error 'm' is not in '{ ... c }' +var callableConstructableSpread; +callableConstructableSpread(12); // error, no call signature +new callableConstructableSpread(12); // error, no construct signature +var callableSpread = __assign({}, publicx, (function (n) { return n + 1; })); // error, can't spread functions diff --git a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt new file mode 100644 index 0000000000000..41651fb1d1c8e --- /dev/null +++ b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt @@ -0,0 +1,35 @@ +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,15): error TS2304: Cannot find name 'o'. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,18): error TS1109: Expression expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,15): error TS1109: Expression expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,16): error TS2304: Cannot find name 'o'. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,15): error TS2304: Cannot find name 'matchMedia'. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,28): error TS1005: ',' expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,31): error TS1128: Declaration or statement expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,16): error TS2304: Cannot find name 'get'. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error TS1005: ',' expected. + + +==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (9 errors) ==== + let o7 = { ...o? }; + ~ +!!! error TS2304: Cannot find name 'o'. + ~ +!!! error TS1109: Expression expected. + let o8 = { ...*o }; + ~ +!!! error TS1109: Expression expected. + ~ +!!! error TS2304: Cannot find name 'o'. + let o9 = { ...matchMedia() { }}; + ~~~~~~~~~~ +!!! error TS2304: Cannot find name 'matchMedia'. + ~ +!!! error TS1005: ',' expected. + ~ +!!! error TS1128: Declaration or statement expected. + let o10 = { ...get x() { return 12; }}; + ~~~ +!!! error TS2304: Cannot find name 'get'. + ~ +!!! error TS1005: ',' expected. + \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegativeParse.js b/tests/baselines/reference/objectSpreadNegativeParse.js new file mode 100644 index 0000000000000..297c56c3e62ae --- /dev/null +++ b/tests/baselines/reference/objectSpreadNegativeParse.js @@ -0,0 +1,21 @@ +//// [objectSpreadNegativeParse.ts] +let o7 = { ...o? }; +let o8 = { ...*o }; +let o9 = { ...matchMedia() { }}; +let o10 = { ...get x() { return 12; }}; + + +//// [objectSpreadNegativeParse.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var o7 = __assign({}, o ? : ); +var o8 = __assign({}, * o); +var o9 = __assign({}, matchMedia()), _a = void 0; +; +var o10 = __assign({}, get, { x: function () { return 12; } }); From 39385590b6b9571d85ab74b43faaf7caddd9c388 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 09:43:59 -0700 Subject: [PATCH 06/85] Move interfaceSpread to correct location --- tests/baselines/reference/interfaceSpread.errors.txt | 8 ++++---- .../destructuring => types/spread}/interfaceSpread.ts | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename tests/cases/conformance/{es6/destructuring => types/spread}/interfaceSpread.ts (100%) diff --git a/tests/baselines/reference/interfaceSpread.errors.txt b/tests/baselines/reference/interfaceSpread.errors.txt index 27aab11491c5a..2b27c972cc895 100644 --- a/tests/baselines/reference/interfaceSpread.errors.txt +++ b/tests/baselines/reference/interfaceSpread.errors.txt @@ -1,9 +1,9 @@ -tests/cases/conformance/es6/destructuring/interfaceSpread.ts(2,5): error TS2699: Interface declaration cannot contain a spread property. -tests/cases/conformance/es6/destructuring/interfaceSpread.ts(7,10): error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. -tests/cases/conformance/es6/destructuring/interfaceSpread.ts(8,10): error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. +tests/cases/conformance/types/spread/interfaceSpread.ts(2,5): error TS2699: Interface declaration cannot contain a spread property. +tests/cases/conformance/types/spread/interfaceSpread.ts(7,10): error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. +tests/cases/conformance/types/spread/interfaceSpread.ts(8,10): error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. -==== tests/cases/conformance/es6/destructuring/interfaceSpread.ts (3 errors) ==== +==== tests/cases/conformance/types/spread/interfaceSpread.ts (3 errors) ==== interface Congealed { ...T ~~~~ diff --git a/tests/cases/conformance/es6/destructuring/interfaceSpread.ts b/tests/cases/conformance/types/spread/interfaceSpread.ts similarity index 100% rename from tests/cases/conformance/es6/destructuring/interfaceSpread.ts rename to tests/cases/conformance/types/spread/interfaceSpread.ts From 63f8c991733ec3f4ba5819452281f91e2206b8ed Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 10:24:05 -0700 Subject: [PATCH 07/85] Object.assign uses spread types now --- src/lib/es2015.core.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 5d570bb086630..2373b828fdd6d 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -278,7 +278,7 @@ interface ObjectConstructor { * @param target The target object to copy to. * @param source The source object from which to copy properties. */ - assign(target: T, source: U): T & U; + assign(target: T, source: U): { ...T, ...U }; /** * Copy the values of all of the enumerable own properties from one or more source objects to a @@ -287,7 +287,7 @@ interface ObjectConstructor { * @param source1 The first source object from which to copy properties. * @param source2 The second source object from which to copy properties. */ - assign(target: T, source1: U, source2: V): T & U & V; + assign(target: T, source1: U, source2: V): { ...T, ...U, ...V }; /** * Copy the values of all of the enumerable own properties from one or more source objects to a @@ -297,7 +297,7 @@ interface ObjectConstructor { * @param source2 The second source object from which to copy properties. * @param source3 The third source object from which to copy properties. */ - assign(target: T, source1: U, source2: V, source3: W): T & U & V & W; + assign(target: T, source1: U, source2: V, source3: W): { ...T, ...U, ...V, ...W }; /** * Copy the values of all of the enumerable own properties from one or more source objects to a From a0db19749ab5316254fdfa7d3dfdaa49aee3ed7a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 11:50:02 -0700 Subject: [PATCH 08/85] Rename Spread[Element]Expression 1. SpreadElementExpression (existing, for arrays) -> SpreadExpression 2. SpreadElement (new for object literals) -> SpreadElementExpression --- src/compiler/binder.ts | 23 +++++++------ src/compiler/checker.ts | 38 +++++++++++----------- src/compiler/emitter.ts | 6 ++-- src/compiler/factory.ts | 6 ++-- src/compiler/parser.ts | 20 +++++------- src/compiler/transformers/destructuring.ts | 4 +-- src/compiler/transformers/es6.ts | 36 ++++++++++---------- src/compiler/transformers/experimental.ts | 4 +-- src/compiler/transformers/module/system.ts | 6 ++-- src/compiler/types.ts | 18 +++++----- src/compiler/utilities.ts | 14 ++++---- src/compiler/visitor.ts | 12 +++---- src/services/breakpoints.ts | 2 +- src/services/utilities.ts | 4 +-- 14 files changed, 96 insertions(+), 97 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index d3217fd70a850..c198b5c01ff59 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1063,8 +1063,8 @@ namespace ts { } else if (node.kind === SyntaxKind.ArrayLiteralExpression) { for (const e of (node).elements) { - if (e.kind === SyntaxKind.SpreadElementExpression) { - bindAssignmentTargetFlow((e).expression); + if (e.kind === SyntaxKind.SpreadExpression) { + bindAssignmentTargetFlow((e).expression); } else { bindDestructuringTargetFlow(e); @@ -1079,6 +1079,9 @@ namespace ts { else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { bindAssignmentTargetFlow((p).name); } + else if (p.kind === SyntaxKind.SpreadElementExpression) { + bindAssignmentTargetFlow((p).expression); + } } } } @@ -1825,7 +1828,7 @@ namespace ts { case SyntaxKind.EnumMember: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes); - case SyntaxKind.SpreadElement: + case SyntaxKind.SpreadElementExpression: case SyntaxKind.JsxSpreadAttribute: emitFlags |= NodeFlags.HasSpreadAttribute; return; @@ -2369,9 +2372,9 @@ namespace ts { const expression = node.expression; const expressionKind = expression.kind; - if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression + if (subtreeFlags & TransformFlags.ContainsSpreadExpression || isSuperOrSuperProperty(expression, expressionKind)) { - // If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6 + // If the this node contains a SpreadExpression, or is a super call, then it is an ES6 // node. transformFlags |= TransformFlags.AssertES6; } @@ -2957,10 +2960,10 @@ namespace ts { } break; - case SyntaxKind.SpreadElement: + case SyntaxKind.SpreadExpression: case SyntaxKind.SpreadElementExpression: // This node is ES6 or ES future syntax, but is handled by a containing node. - transformFlags |= TransformFlags.ContainsSpreadElementExpression; + transformFlags |= TransformFlags.ContainsSpreadExpression; break; case SyntaxKind.SuperKeyword: @@ -2998,7 +3001,7 @@ namespace ts { transformFlags |= TransformFlags.ContainsLexicalThis; } - if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) { + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { // If an ObjectLiteralExpression contains a spread element, then it // is an ES experimental node. transformFlags |= TransformFlags.AssertExperimental; @@ -3009,8 +3012,8 @@ namespace ts { case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.NewExpression: excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes; - if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) { - // If the this node contains a SpreadElementExpression, then it is an ES6 + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + // If the this node contains a SpreadExpression, then it is an ES6 // node. transformFlags |= TransformFlags.AssertES6; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3578aeb5e4bb9..1f31d58b19709 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8379,7 +8379,7 @@ namespace ts { unknownType; } - function getTypeOfDestructuredSpreadElement(type: Type) { + function getTypeOfDestructuredSpreadExpression(type: Type) { return createArrayType(checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false) || unknownType); } @@ -8393,8 +8393,8 @@ namespace ts { return getTypeOfDestructuredArrayElement(getAssignedType(node), indexOf(node.elements, element)); } - function getAssignedTypeOfSpreadElement(node: SpreadElementExpression): Type { - return getTypeOfDestructuredSpreadElement(getAssignedType(node.parent)); + function getAssignedTypeOfSpreadExpression(node: SpreadExpression): Type { + return getTypeOfDestructuredSpreadExpression(getAssignedType(node.parent)); } function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type { @@ -8418,8 +8418,8 @@ namespace ts { return undefinedType; case SyntaxKind.ArrayLiteralExpression: return getAssignedTypeOfArrayLiteralElement(parent, node); - case SyntaxKind.SpreadElementExpression: - return getAssignedTypeOfSpreadElement(parent); + case SyntaxKind.SpreadExpression: + return getAssignedTypeOfSpreadExpression(parent); case SyntaxKind.PropertyAssignment: return getAssignedTypeOfPropertyAssignment(parent); case SyntaxKind.ShorthandPropertyAssignment: @@ -8435,7 +8435,7 @@ namespace ts { getTypeOfDestructuredProperty(parentType, node.propertyName || node.name) : !node.dotDotDotToken ? getTypeOfDestructuredArrayElement(parentType, indexOf(pattern.elements, node)) : - getTypeOfDestructuredSpreadElement(parentType); + getTypeOfDestructuredSpreadExpression(parentType); return getTypeWithDefault(type, node.initializer); } @@ -10221,7 +10221,7 @@ namespace ts { return mapper && mapper.context; } - function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type { + function checkSpreadExpression(node: SpreadExpression, contextualMapper?: TypeMapper): Type { // It is usually not safe to call checkExpressionCached if we can be contextually typing. // You can tell that we are contextually typing because of the contextualMapper parameter. // While it is true that a spread element can have a contextual type, it does not do anything @@ -10243,7 +10243,7 @@ namespace ts { const elementTypes: Type[] = []; const inDestructuringPattern = isAssignmentTarget(node); for (const e of elements) { - if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) { + if (inDestructuringPattern && e.kind === SyntaxKind.SpreadExpression) { // Given the following situation: // var c: {}; // [...c] = ["", 0]; @@ -10256,7 +10256,7 @@ namespace ts { // get the contextual element type from it. So we do something similar to // getContextualTypeForElementExpression, which will crucially not error // if there is no index type / iterated type. - const restArrayType = checkExpression((e).expression, contextualMapper); + const restArrayType = checkExpression((e).expression, contextualMapper); const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) || (languageVersion >= ScriptTarget.ES6 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined); if (restElementType) { @@ -10267,7 +10267,7 @@ namespace ts { const type = checkExpressionForMutableLocation(e, contextualMapper); elementTypes.push(type); } - hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression; + hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadExpression; } if (!hasSpreadElement) { // If array literal is actually a destructuring pattern, mark it as an implied type. We do this such @@ -10456,7 +10456,7 @@ namespace ts { prop.target = member; member = prop; } - else if (memberDecl.kind === SyntaxKind.SpreadElement) { + else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { if (propertiesArray.length > 0) { const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType; t.isDeclaredProperty = true; @@ -10466,7 +10466,7 @@ namespace ts { hasComputedStringProperty = false; hasComputedNumberProperty = false; } - spreads.push(checkExpression((memberDecl as SpreadElement).target) as SpreadElementType); + spreads.push(checkExpression((memberDecl as SpreadElementExpression).expression) as SpreadElementType); continue; } else { @@ -11503,7 +11503,7 @@ namespace ts { function getSpreadArgumentIndex(args: Expression[]): number { for (let i = 0; i < args.length; i++) { const arg = args[i]; - if (arg && arg.kind === SyntaxKind.SpreadElementExpression) { + if (arg && arg.kind === SyntaxKind.SpreadExpression) { return i; } } @@ -13474,7 +13474,7 @@ namespace ts { const elements = node.elements; const element = elements[elementIndex]; if (element.kind !== SyntaxKind.OmittedExpression) { - if (element.kind !== SyntaxKind.SpreadElementExpression) { + if (element.kind !== SyntaxKind.SpreadExpression) { const propName = "" + elementIndex; const type = isTypeAny(sourceType) ? sourceType @@ -13501,7 +13501,7 @@ namespace ts { error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); } else { - const restExpression = (element).expression; + const restExpression = (element).expression; if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression).operatorToken.kind === SyntaxKind.EqualsToken) { error((restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); } @@ -14137,8 +14137,8 @@ namespace ts { return checkBinaryExpression(node, contextualMapper); case SyntaxKind.ConditionalExpression: return checkConditionalExpression(node, contextualMapper); - case SyntaxKind.SpreadElementExpression: - return checkSpreadElementExpression(node, contextualMapper); + case SyntaxKind.SpreadExpression: + return checkSpreadExpression(node, contextualMapper); case SyntaxKind.OmittedExpression: return undefinedWideningType; case SyntaxKind.YieldExpression: @@ -20048,8 +20048,8 @@ namespace ts { const GetOrSetAccessor = GetAccessor | SetAccessor; for (const prop of node.properties) { - if (prop.kind === SyntaxKind.SpreadElement) { - const target = (prop as SpreadElement).target; + if (prop.kind === SyntaxKind.SpreadElementExpression) { + const target = (prop as SpreadElementExpression).expression; switch (target.kind) { case SyntaxKind.Identifier: case SyntaxKind.PropertyAccessExpression: diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index cd00f7ad76905..cc574414beb63 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -824,8 +824,8 @@ const _super = (function (geti, seti) { return emitTemplateExpression(node); case SyntaxKind.YieldExpression: return emitYieldExpression(node); - case SyntaxKind.SpreadElementExpression: - return emitSpreadElementExpression(node); + case SyntaxKind.SpreadExpression: + return emitSpreadExpression(node); case SyntaxKind.ClassExpression: return emitClassExpression(node); case SyntaxKind.OmittedExpression: @@ -1365,7 +1365,7 @@ const _super = (function (geti, seti) { emitExpressionWithPrefix(" ", node.expression); } - function emitSpreadElementExpression(node: SpreadElementExpression) { + function emitSpreadExpression(node: SpreadExpression) { write("..."); emitExpression(node.expression); } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 16eeb86f59a73..a8ee15c12c409 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -704,12 +704,12 @@ namespace ts { } export function createSpread(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.SpreadElementExpression, location); + const node = createNode(SyntaxKind.SpreadExpression, location); node.expression = parenthesizeExpressionForList(expression); return node; } - export function updateSpread(node: SpreadElementExpression, expression: Expression) { + export function updateSpread(node: SpreadExpression, expression: Expression) { if (node.expression !== expression) { return updateNode(createSpread(expression, node), node); } @@ -2745,4 +2745,4 @@ namespace ts { function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); } -} \ No newline at end of file +} diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ae88b6d948b5b..e0d8790d14ccc 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -74,9 +74,8 @@ namespace ts { visitNode(cbNode, (node).questionToken) || visitNode(cbNode, (node).equalsToken) || visitNode(cbNode, (node).objectAssignmentInitializer); - case SyntaxKind.SpreadElement: - return visitNode(cbNode, (node).dotDotDotToken) || - visitNode(cbNode, (node).target); + case SyntaxKind.SpreadElementExpression: + return visitNode(cbNode, (node).expression); case SyntaxKind.SpreadTypeElement: return visitNode(cbNode, (node as SpreadTypeElement).type); case SyntaxKind.Parameter: @@ -198,8 +197,8 @@ namespace ts { visitNode(cbNode, (node).whenTrue) || visitNode(cbNode, (node).colonToken) || visitNode(cbNode, (node).whenFalse); - case SyntaxKind.SpreadElementExpression: - return visitNode(cbNode, (node).expression); + case SyntaxKind.SpreadExpression: + return visitNode(cbNode, (node).expression); case SyntaxKind.Block: case SyntaxKind.ModuleBlock: return visitNodes(cbNodes, (node).statements); @@ -4102,15 +4101,15 @@ namespace ts { return finishNode(node); } - function parseSpreadElement(): Expression { - const node = createNode(SyntaxKind.SpreadElementExpression); + function parseSpreadExpression(): Expression { + const node = createNode(SyntaxKind.SpreadExpression); parseExpected(SyntaxKind.DotDotDotToken); node.expression = parseAssignmentExpressionOrHigher(); return finishNode(node); } function parseArgumentOrArrayLiteralElement(): Expression { - return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : + return token() === SyntaxKind.DotDotDotToken ? parseSpreadExpression() : token() === SyntaxKind.CommaToken ? createNode(SyntaxKind.OmittedExpression) : parseAssignmentExpressionOrHigher(); } @@ -4145,9 +4144,8 @@ namespace ts { const fullStart = scanner.getStartPos(); const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); if (dotDotDotToken) { - const spreadElement = createNode(SyntaxKind.SpreadElement, fullStart); - spreadElement.dotDotDotToken = dotDotDotToken; - spreadElement.target = parseAssignmentExpressionOrHigher(); + const spreadElement = createNode(SyntaxKind.SpreadElementExpression, fullStart); + spreadElement.expression = parseAssignmentExpressionOrHigher(); return addJSDocComment(finishNode(spreadElement)); } const decorators = parseDecorators(); diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index a66f5e21d784d..7d74e58f204ae 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -310,11 +310,11 @@ namespace ts { const e = elements[i]; if (e.kind !== SyntaxKind.OmittedExpression) { // Assignment for target = value.propName should highligh whole property, hence use e as source map node - if (e.kind !== SyntaxKind.SpreadElementExpression) { + if (e.kind !== SyntaxKind.SpreadExpression) { emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e); } else if (i === numElements - 1) { - emitDestructuringAssignment((e).expression, createArraySlice(value, i), e); + emitDestructuringAssignment((e).expression, createArraySlice(value, i), e); } } } diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 114a3aea54684..7582b14e4aaf1 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -2556,7 +2556,7 @@ namespace ts { // because we contain a SpreadElementExpression. const { target, thisArg } = createCallBinding(node.expression, hoistVariableDeclaration); - if (node.transformFlags & TransformFlags.ContainsSpreadElementExpression) { + if (node.transformFlags & TransformFlags.ContainsSpreadExpression) { // [source] // f(...a, b) // x.m(...a, b) @@ -2604,7 +2604,7 @@ namespace ts { */ function visitNewExpression(node: NewExpression): LeftHandSideExpression { // We are here because we contain a SpreadElementExpression. - Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadElementExpression) !== 0); + Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadExpression) !== 0); // [source] // new C(...a) @@ -2625,7 +2625,7 @@ namespace ts { } /** - * Transforms an array of Expression nodes that contains a SpreadElementExpression. + * Transforms an array of Expression nodes that contains a SpreadExpression. * * @param elements The array of Expression nodes. * @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array. @@ -2642,14 +2642,14 @@ namespace ts { // expressions into an array literal. const numElements = elements.length; const segments = flatten( - spanMap(elements, partitionSpreadElement, (partition, visitPartition, start, end) => + spanMap(elements, partitionSpread, (partition, visitPartition, start, end) => visitPartition(partition, multiLine, hasTrailingComma && end === numElements) ) ); if (segments.length === 1) { const firstElement = elements[0]; - return needsUniqueCopy && isSpreadElementExpression(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression + return needsUniqueCopy && isSpreadExpression(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression ? createArraySlice(segments[0]) : segments[0]; } @@ -2658,17 +2658,17 @@ namespace ts { return createArrayConcat(segments.shift(), segments); } - function partitionSpreadElement(node: Expression) { - return isSpreadElementExpression(node) - ? visitSpanOfSpreadElements - : visitSpanOfNonSpreadElements; + function partitionSpread(node: Expression) { + return isSpreadExpression(node) + ? visitSpanOfSpreads + : visitSpanOfNonSpreads; } - function visitSpanOfSpreadElements(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { - return map(chunk, visitExpressionOfSpreadElement); + function visitSpanOfSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { + return map(chunk, visitExpressionOfSpread); } - function visitSpanOfNonSpreadElements(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { + function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { return createArrayLiteral( visitNodes(createNodeArray(chunk, /*location*/ undefined, hasTrailingComma), visitor, isExpression), /*location*/ undefined, @@ -2677,11 +2677,11 @@ namespace ts { } /** - * Transforms the expression of a SpreadElementExpression node. + * Transforms the expression of a SpreadExpression node. * - * @param node A SpreadElementExpression node. + * @param node A SpreadExpression node. */ - function visitExpressionOfSpreadElement(node: SpreadElementExpression) { + function visitExpressionOfSpread(node: SpreadExpression) { return visitNode(node.expression, visitor, isExpression); } @@ -3096,12 +3096,12 @@ namespace ts { } const callArgument = singleOrUndefined((statementExpression).arguments); - if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElementExpression) { + if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadExpression) { return false; } - const expression = (callArgument).expression; + const expression = (callArgument).expression; return isIdentifier(expression) && expression === parameter.name; } } -} \ No newline at end of file +} diff --git a/src/compiler/transformers/experimental.ts b/src/compiler/transformers/experimental.ts index 715cf91afd3e6..85af37709c744 100644 --- a/src/compiler/transformers/experimental.ts +++ b/src/compiler/transformers/experimental.ts @@ -36,12 +36,12 @@ namespace ts { let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; const objects: Expression[] = []; for (const e of elements) { - if (e.kind === SyntaxKind.SpreadElement) { + if (e.kind === SyntaxKind.SpreadElementExpression) { if (chunkObject) { objects.push(createObjectLiteral(chunkObject)); chunkObject = undefined; } - const target = (e as SpreadElement).target; + const target = (e as SpreadElementExpression).expression; objects.push(visitNode(target, visitor, isExpression)); } else { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 7b013e18e7dc0..de1522a015085 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -1120,7 +1120,7 @@ namespace ts { } function hasExportedReferenceInArrayDestructuringElement(node: Expression): boolean { - if (isSpreadElementExpression(node)) { + if (isSpreadExpression(node)) { const expression = node.expression; return isIdentifier(expression) && isExportedBinding(expression); } @@ -1139,7 +1139,7 @@ namespace ts { else if (isIdentifier(node)) { return isExportedBinding(node); } - else if (isSpreadElementExpression(node)) { + else if (isSpreadExpression(node)) { const expression = node.expression; return isIdentifier(expression) && isExportedBinding(expression); } @@ -1400,4 +1400,4 @@ namespace ts { return updated; } } -} \ No newline at end of file +} diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cdf42ebea4ffc..bfadea3179420 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -241,7 +241,7 @@ namespace ts { ConditionalExpression, TemplateExpression, YieldExpression, - SpreadElementExpression, + SpreadExpression, ClassExpression, OmittedExpression, ExpressionWithTypeArguments, @@ -316,8 +316,8 @@ namespace ts { // Property assignments PropertyAssignment, ShorthandPropertyAssignment, - SpreadElement, // maybe name it SpreadProperty? - SpreadTypeElement, // maybe name it SpreadTypeNode? + SpreadElementExpression, + SpreadTypeElement, // Enum @@ -674,9 +674,7 @@ namespace ts { } // @kind(SyntaxKind.SpreadElementExpression) - export interface SpreadElement extends ObjectLiteralElement { - dotDotDotToken: Node; - target: Expression; + export interface SpreadElementExpression extends ObjectLiteralElement, SpreadExpression { } // SyntaxKind.VariableDeclaration @@ -1056,8 +1054,8 @@ namespace ts { multiLine?: boolean; } - // @kind(SyntaxKind.SpreadElementExpression) - export interface SpreadElementExpression extends Expression { + // @kind(SyntaxKind.SpreadExpression) + export interface SpreadExpression extends Expression { expression: Expression; } @@ -3140,7 +3138,7 @@ namespace ts { ContainsLexicalThisInComputedPropertyName = 1 << 17, ContainsDefaultValueAssignments = 1 << 18, ContainsParameterPropertyAssignments = 1 << 19, - ContainsSpreadElementExpression = 1 << 20, + ContainsSpreadExpression = 1 << 20, ContainsComputedPropertyName = 1 << 21, ContainsBlockScopedBinding = 1 << 22, ContainsBindingPattern = 1 << 23, @@ -3170,7 +3168,7 @@ namespace ts { ModuleExcludes = NodeExcludes | ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion, TypeExcludes = ~ContainsTypeScript, ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName, - ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadElementExpression, + ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadExpression, VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern, ParameterExcludes = NodeExcludes | ContainsBindingPattern, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 67ea182bf9868..30a09ade0f596 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1178,7 +1178,7 @@ namespace ts { case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.BinaryExpression: case SyntaxKind.ConditionalExpression: - case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SpreadExpression: case SyntaxKind.TemplateExpression: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.OmittedExpression: @@ -1633,7 +1633,7 @@ namespace ts { } while (true) { const parent = node.parent; - if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.SpreadElementExpression) { + if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.SpreadExpression) { node = parent; continue; } @@ -2209,7 +2209,7 @@ namespace ts { case SyntaxKind.YieldExpression: return 2; - case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SpreadExpression: return 1; default: @@ -3740,7 +3740,7 @@ namespace ts { const kind = node.kind; return kind === SyntaxKind.PropertyAssignment || kind === SyntaxKind.ShorthandPropertyAssignment - || kind === SyntaxKind.SpreadElement + || kind === SyntaxKind.SpreadElementExpression || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor @@ -3820,8 +3820,8 @@ namespace ts { || kind === SyntaxKind.NoSubstitutionTemplateLiteral; } - export function isSpreadElementExpression(node: Node): node is SpreadElementExpression { - return node.kind === SyntaxKind.SpreadElementExpression; + export function isSpreadExpression(node: Node): node is SpreadExpression { + return node.kind === SyntaxKind.SpreadExpression; } export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments { @@ -3879,7 +3879,7 @@ namespace ts { || kind === SyntaxKind.YieldExpression || kind === SyntaxKind.ArrowFunction || kind === SyntaxKind.BinaryExpression - || kind === SyntaxKind.SpreadElementExpression + || kind === SyntaxKind.SpreadExpression || kind === SyntaxKind.AsExpression || kind === SyntaxKind.OmittedExpression || isUnaryExpressionKind(kind); diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 1e0cadaaa6b99..691e13b03d69c 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -267,9 +267,9 @@ namespace ts { case SyntaxKind.VoidExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.YieldExpression: - case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SpreadExpression: case SyntaxKind.NonNullExpression: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, f, result); break; case SyntaxKind.PrefixUnaryExpression: @@ -869,9 +869,9 @@ namespace ts { return updateYield(node, visitNode((node).expression, visitor, isExpression)); - case SyntaxKind.SpreadElementExpression: - return updateSpread(node, - visitNode((node).expression, visitor, isExpression)); + case SyntaxKind.SpreadExpression: + return updateSpread(node, + visitNode((node).expression, visitor, isExpression)); case SyntaxKind.ClassExpression: return updateClassExpression(node, @@ -1357,4 +1357,4 @@ namespace ts { } } } -} \ No newline at end of file +} diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index bf7fb981daaca..f1cc233e67680 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -264,7 +264,7 @@ namespace ts.BreakpointResolver { // a or ...c or d: x from // [a, b, ...c] or { a, b } or { d: x } from destructuring pattern if ((node.kind === SyntaxKind.Identifier || - node.kind == SyntaxKind.SpreadElementExpression || + node.kind == SyntaxKind.SpreadExpression || node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index d1f3a54563f91..e5de4437a5eca 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -530,8 +530,8 @@ namespace ts { case SyntaxKind.DeleteExpression: case SyntaxKind.VoidExpression: case SyntaxKind.YieldExpression: - case SyntaxKind.SpreadElementExpression: - const unaryWordExpression = (n); + case SyntaxKind.SpreadExpression: + const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadExpression); return isCompletedNode(unaryWordExpression.expression, sourceFile); case SyntaxKind.TaggedTemplateExpression: From 9a7ebb0ac5eadf9630577b11eb0064c04ed6cd44 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 26 Sep 2016 11:53:11 -0700 Subject: [PATCH 09/85] Change new file to use CRLF What's YOUR favourite thing about Mars, Beartato? --- src/compiler/transformers/experimental.ts | 160 +++++++++++----------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/src/compiler/transformers/experimental.ts b/src/compiler/transformers/experimental.ts index 85af37709c744..2ee623db43aed 100644 --- a/src/compiler/transformers/experimental.ts +++ b/src/compiler/transformers/experimental.ts @@ -1,80 +1,80 @@ -/// -/// - -/*@internal*/ -namespace ts { - export function transformExperimental(context: TransformationContext) { - return transformSourceFile; - - function transformSourceFile(node: SourceFile) { - return visitEachChild(node, visitor, context); - } - - function visitor(node: Node): VisitResult { - if (node.transformFlags & TransformFlags.Experimental) { - return visitorWorker(node); - } - else if (node.transformFlags & TransformFlags.ContainsExperimental) { - return visitEachChild(node, visitor, context); - } - else { - return node; - } - } - - function visitorWorker(node: Node): VisitResult { - switch (node.kind) { - case SyntaxKind.ObjectLiteralExpression: - return visitObjectLiteralExpression(node as ObjectLiteralExpression); - default: - Debug.failBadSyntaxKind(node); - return visitEachChild(node, visitor, context); - } - } - - function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] { - let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; - const objects: Expression[] = []; - for (const e of elements) { - if (e.kind === SyntaxKind.SpreadElementExpression) { - if (chunkObject) { - objects.push(createObjectLiteral(chunkObject)); - chunkObject = undefined; - } - const target = (e as SpreadElementExpression).expression; - objects.push(visitNode(target, visitor, isExpression)); - } - else { - if (!chunkObject) { - chunkObject = []; - } - if (e.kind === SyntaxKind.PropertyAssignment) { - const p = e as PropertyAssignment; - chunkObject.push(createPropertyAssignment(p.name, visitNode(p.initializer, visitor, isExpression))); - } - else { - chunkObject.push(e as ShorthandPropertyAssignment); - } - } - } - if (chunkObject) { - objects.push(createObjectLiteral(chunkObject)); - } - - return objects; - } - - function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression { - // spread elements emit like so: - // non-spread elements are chunked together into object literals, and then all are passed to __assign: - // { a, ...o, b } => __assign({a}, o, {b}); - // If the first element is a spread element, then the first argument to __assign is {}: - // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2) - const objects = chunkObjectLiteralElements(node.properties); - if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { - objects.unshift(createObjectLiteral()); - } - return createCall(createIdentifier("__assign"), undefined, objects); - } - } -} +/// +/// + +/*@internal*/ +namespace ts { + export function transformExperimental(context: TransformationContext) { + return transformSourceFile; + + function transformSourceFile(node: SourceFile) { + return visitEachChild(node, visitor, context); + } + + function visitor(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.Experimental) { + return visitorWorker(node); + } + else if (node.transformFlags & TransformFlags.ContainsExperimental) { + return visitEachChild(node, visitor, context); + } + else { + return node; + } + } + + function visitorWorker(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.ObjectLiteralExpression: + return visitObjectLiteralExpression(node as ObjectLiteralExpression); + default: + Debug.failBadSyntaxKind(node); + return visitEachChild(node, visitor, context); + } + } + + function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] { + let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; + const objects: Expression[] = []; + for (const e of elements) { + if (e.kind === SyntaxKind.SpreadElementExpression) { + if (chunkObject) { + objects.push(createObjectLiteral(chunkObject)); + chunkObject = undefined; + } + const target = (e as SpreadElementExpression).expression; + objects.push(visitNode(target, visitor, isExpression)); + } + else { + if (!chunkObject) { + chunkObject = []; + } + if (e.kind === SyntaxKind.PropertyAssignment) { + const p = e as PropertyAssignment; + chunkObject.push(createPropertyAssignment(p.name, visitNode(p.initializer, visitor, isExpression))); + } + else { + chunkObject.push(e as ShorthandPropertyAssignment); + } + } + } + if (chunkObject) { + objects.push(createObjectLiteral(chunkObject)); + } + + return objects; + } + + function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression { + // spread elements emit like so: + // non-spread elements are chunked together into object literals, and then all are passed to __assign: + // { a, ...o, b } => __assign({a}, o, {b}); + // If the first element is a spread element, then the first argument to __assign is {}: + // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2) + const objects = chunkObjectLiteralElements(node.properties); + if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { + objects.unshift(createObjectLiteral()); + } + return createCall(createIdentifier("__assign"), undefined, objects); + } + } +} From cfdf75176863a08fd9112649d9c5a34acd7e6505 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 27 Sep 2016 10:30:13 -0700 Subject: [PATCH 10/85] Make index signatures work on spread types Previously, they worked when they came from a spread type but not when written in the object literal itself. --- src/compiler/checker.ts | 59 ++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1f31d58b19709..66a5d9fc4153d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2321,6 +2321,9 @@ namespace ts { printFollowingPunctuation = true; } } + const resolved = resolveStructuredTypeMembers(type); + writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword); + writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword); writer.decreaseIndent(); if (printFollowingPunctuation) { writeSpace(writer); @@ -4306,15 +4309,14 @@ namespace ts { function resolveSpreadTypeMembers(type: SpreadType) { // The members and properties collections are empty for spread types. To get all properties of an - // spread type use getPropertiesOfType (only the language service uses this). - let stringIndexInfo: IndexInfo = undefined; - let numberIndexInfo: IndexInfo = undefined; + // spread type use getPropertiesOfType. + let stringIndexInfo: IndexInfo = getIndexInfoOfSymbol(type.symbol, IndexKind.String); + let numberIndexInfo: IndexInfo = getIndexInfoOfSymbol(type.symbol, IndexKind.Number); for (let i = type.types.length - 1; i > -1; i--) { const t = type.types[i]; - stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); - numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); - if (!t.symbol || !(t.symbol.flags & SymbolFlags.Optional)) { - break; + if (!t.isDeclaredProperty) { + stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); + numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); } } setObjectTypeMembers(type, emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); @@ -4545,6 +4547,9 @@ namespace ts { result.containingType = containingType; result.hasCommonType = hasCommonType; result.declarations = declarations; + if (declarations.length) { + result.valueDeclaration = declarations[0]; + } result.isReadonly = isReadonly; result.type = containingType.flags & TypeFlags.Intersection ? getIntersectionType(propTypes) : getUnionType(propTypes); return result; @@ -5059,7 +5064,7 @@ namespace ts { const declaration = getIndexDeclarationOfSymbol(symbol, kind); if (declaration) { return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, - (getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration); + (getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration); } return undefined; } @@ -5683,11 +5688,15 @@ namespace ts { } spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type) as SpreadElementType); } - else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) { - // note that spread types don't include call and construct signatures + else if (member.kind !== SyntaxKind.CallSignature && + member.kind !== SyntaxKind.ConstructSignature && + member.kind !== SyntaxKind.IndexSignature) { + // note that spread types don't include call and construct signatures, and index signatures are resolved later const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); const text = getTextOfPropertyName(member.name); const symbol = createSymbol(flags, text); + symbol.declarations = [member]; + symbol.valueDeclaration = member; symbol.type = getTypeFromTypeNodeNoAlias((member as IndexSignatureDeclaration | PropertySignature | MethodSignature).type); if (!members) { members = createMap(); @@ -10458,7 +10467,7 @@ namespace ts { } else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { if (propertiesArray.length > 0) { - const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType; + const t = createObjectLiteralType() as SpreadElementType; t.isDeclaredProperty = true; spreads.push(t); propertiesArray = []; @@ -10510,7 +10519,7 @@ namespace ts { if (spreads.length > 0) { if (propertiesArray.length > 0) { - const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType; + const t = createObjectLiteralType() as SpreadElementType; t.isDeclaredProperty = true; spreads.push(t); } @@ -10520,20 +10529,20 @@ namespace ts { return spread; } - return createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern); - } - - function createObjectLiteralType(node: ObjectLiteralExpression, hasComputedStringProperty: boolean, hasComputedNumberProperty: boolean, propertiesArray: Symbol[], propertiesTable: Map, typeFlags: TypeFlags, patternWithComputedProperties: boolean, inDestructuringPattern: boolean) { - const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined; - const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; - const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); - const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral; - result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0); - if (inDestructuringPattern) { - result.pattern = node; + return createObjectLiteralType(); + function createObjectLiteralType() { + const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined; + const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; + const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral; + result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0); + if (inDestructuringPattern) { + result.pattern = node; + } + return result; } - return result; - } + + } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { checkJsxOpeningLikeElement(node); From d6e414ce5b3e9532dd05651854f1d2f694de6e8c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 27 Sep 2016 10:33:50 -0700 Subject: [PATCH 11/85] Test spread type index signatures --- .../reference/objectSpreadIndexSignature.js | 29 ++++++++++ .../objectSpreadIndexSignature.symbols | 51 +++++++++++++++++ .../objectSpreadIndexSignature.types | 57 +++++++++++++++++++ .../spread/objectSpreadIndexSignature.ts | 14 +++++ 4 files changed, 151 insertions(+) create mode 100644 tests/baselines/reference/objectSpreadIndexSignature.js create mode 100644 tests/baselines/reference/objectSpreadIndexSignature.symbols create mode 100644 tests/baselines/reference/objectSpreadIndexSignature.types create mode 100644 tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js new file mode 100644 index 0000000000000..c4a0d6b90d8a8 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -0,0 +1,29 @@ +//// [objectSpreadIndexSignature.ts] +class C { + a: number; + c: boolean; +} +let c: { ...C, b: string, c?: string, [n: number]: string }; +let n: number = c.a; +let s: string = c[12]; +interface Indexed { + [n: number]: string; + a: boolean; +} +let i: { ...Indexed, b: string }; +s = i[101]; +s = i.b; + + +//// [objectSpreadIndexSignature.js] +var C = (function () { + function C() { + } + return C; +}()); +var c; +var n = c.a; +var s = c[12]; +var i; +s = i[101]; +s = i.b; diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols new file mode 100644 index 0000000000000..fee1e862adea6 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIndexSignature.symbols @@ -0,0 +1,51 @@ +=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === +class C { +>C : Symbol(C, Decl(objectSpreadIndexSignature.ts, 0, 0)) + + a: number; +>a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) + + c: boolean; +>c : Symbol(C.c, Decl(objectSpreadIndexSignature.ts, 1, 14)) +} +let c: { ...C, b: string, c?: string, [n: number]: string }; +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 3)) +>C : Symbol(C, Decl(objectSpreadIndexSignature.ts, 0, 0)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 4, 14)) +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 25)) +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 4, 39)) + +let n: number = c.a; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 3)) +>c.a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 3)) +>a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) + +let s: string = c[12]; +>s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 6, 3)) +>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 3)) + +interface Indexed { +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) + + [n: number]: string; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 8, 5)) + + a: boolean; +>a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 8, 24)) +} +let i: { ...Indexed, b: string }; +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) + +s = i[101]; +>s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 6, 3)) +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) + +s = i.b; +>s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 6, 3)) +>i.b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) + diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types new file mode 100644 index 0000000000000..9adbb349da2d2 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -0,0 +1,57 @@ +=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === +class C { +>C : C + + a: number; +>a : number + + c: boolean; +>c : boolean +} +let c: { ...C, b: string, c?: string, [n: number]: string }; +>c : { ...C; b: string; c?: string; [n: number]: string; } +>C : C +>b : string +>c : string +>n : number + +let n: number = c.a; +>n : number +>c.a : number +>c : { ...C; b: string; c?: string; [n: number]: string; } +>a : number + +let s: string = c[12]; +>s : string +>c[12] : string +>c : { ...C; b: string; c?: string; [n: number]: string; } +>12 : 12 + +interface Indexed { +>Indexed : Indexed + + [n: number]: string; +>n : number + + a: boolean; +>a : boolean +} +let i: { ...Indexed, b: string }; +>i : { ...Indexed; b: string; [n: number]: string; } +>Indexed : Indexed +>b : string + +s = i[101]; +>s = i[101] : string +>s : string +>i[101] : string +>i : { ...Indexed; b: string; [n: number]: string; } +>101 : 101 + +s = i.b; +>s = i.b : string +>s : string +>i.b : string +>i : { ...Indexed; b: string; [n: number]: string; } +>b : string + diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts new file mode 100644 index 0000000000000..11ba545008504 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -0,0 +1,14 @@ +class C { + a: number; + c: boolean; +} +let c: { ...C, b: string, c?: string, [n: number]: string }; +let n: number = c.a; +let s: string = c[12]; +interface Indexed { + [n: number]: string; + a: boolean; +} +let i: { ...Indexed, b: string }; +s = i[101]; +s = i.b; From 429b0d95ca54538cabdd09e59eeca71661fe72d9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 27 Sep 2016 11:05:12 -0700 Subject: [PATCH 12/85] Union multiple spread index signatures --- src/compiler/checker.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 66a5d9fc4153d..e1e7cce4df41c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2321,6 +2321,8 @@ namespace ts { printFollowingPunctuation = true; } } + // TODO: Only print if this is directly on the type -- not on the subtype somewhere. + // (This is not crucial, though, since the extra info *might* be nice.) const resolved = resolveStructuredTypeMembers(type); writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword); writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword); @@ -4291,6 +4293,11 @@ namespace ts { getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly); } + function unionIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo { + return !info1 ? info2 : !info2 ? info1 : createIndexInfo( + getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); + } + function resolveIntersectionTypeMembers(type: IntersectionType) { // The members and properties collections are empty for intersection types. To get all properties of an // intersection type use getPropertiesOfType (only the language service uses this). @@ -4315,8 +4322,8 @@ namespace ts { for (let i = type.types.length - 1; i > -1; i--) { const t = type.types[i]; if (!t.isDeclaredProperty) { - stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); - numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); + stringIndexInfo = unionIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); + numberIndexInfo = unionIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); } } setObjectTypeMembers(type, emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); @@ -16839,7 +16846,9 @@ namespace ts { // perform property check if property or indexer is declared in 'type' // this allows to rule out cases when both property and indexer are inherited from the base class let errorNode: Node; - if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { + if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || + prop.parent === containingType.symbol || + containingType.flags & TypeFlags.Spread) { errorNode = prop.valueDeclaration; } else if (indexDeclaration) { From 78420adfcdf67a9e79025edee9a33e886c72ba94 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 27 Sep 2016 11:05:58 -0700 Subject: [PATCH 13/85] Test object spread index signatures --- .../reference/objectSpreadIndexSignature.js | 22 ++++--- .../objectSpreadIndexSignature.symbols | 34 ++++++++--- .../objectSpreadIndexSignature.types | 58 +++++++++++++------ .../spread/objectSpreadIndexSignature.ts | 16 +++-- 4 files changed, 93 insertions(+), 37 deletions(-) diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js index c4a0d6b90d8a8..b5ec35277e0c3 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.js +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -7,12 +7,18 @@ let c: { ...C, b: string, c?: string, [n: number]: string }; let n: number = c.a; let s: string = c[12]; interface Indexed { - [n: number]: string; - a: boolean; + [n: string]: number; + a: number; +} +let i: { ...Indexed, b: number }; +n = i[101]; +n = i.b; +interface Indexed2 { + [n: string]: boolean; + c: boolean; } -let i: { ...Indexed, b: string }; -s = i[101]; -s = i.b; +let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; +let nb: number | boolean = ii[1001]; //// [objectSpreadIndexSignature.js] @@ -25,5 +31,7 @@ var c; var n = c.a; var s = c[12]; var i; -s = i[101]; -s = i.b; +n = i[101]; +n = i.b; +var ii; +var nb = ii[1001]; diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols index fee1e862adea6..a3510f9865830 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.symbols +++ b/tests/baselines/reference/objectSpreadIndexSignature.symbols @@ -28,24 +28,44 @@ let s: string = c[12]; interface Indexed { >Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) - [n: number]: string; + [n: string]: number; >n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 8, 5)) - a: boolean; + a: number; >a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 8, 24)) } -let i: { ...Indexed, b: string }; +let i: { ...Indexed, b: number }; >i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) >Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) >b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) -s = i[101]; ->s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 6, 3)) +n = i[101]; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 3)) >i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) -s = i.b; ->s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 6, 3)) +n = i.b; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 3)) >i.b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) >i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) >b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) +interface Indexed2 { +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 13, 8)) + + [n: string]: boolean; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 15, 5)) + + c: boolean; +>c : Symbol(Indexed2.c, Decl(objectSpreadIndexSignature.ts, 15, 25)) +} +let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; +>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 18, 3)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 13, 8)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 18, 34)) +>d : Symbol(d, Decl(objectSpreadIndexSignature.ts, 18, 46)) + +let nb: number | boolean = ii[1001]; +>nb : Symbol(nb, Decl(objectSpreadIndexSignature.ts, 19, 3)) +>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 18, 3)) + diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types index 9adbb349da2d2..9a31b0c44512b 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -30,28 +30,50 @@ let s: string = c[12]; interface Indexed { >Indexed : Indexed - [n: number]: string; ->n : number + [n: string]: number; +>n : string - a: boolean; ->a : boolean + a: number; +>a : number } -let i: { ...Indexed, b: string }; ->i : { ...Indexed; b: string; [n: number]: string; } +let i: { ...Indexed, b: number }; +>i : { ...Indexed; b: number; [n: string]: number; } >Indexed : Indexed ->b : string +>b : number -s = i[101]; ->s = i[101] : string ->s : string ->i[101] : string ->i : { ...Indexed; b: string; [n: number]: string; } +n = i[101]; +>n = i[101] : number +>n : number +>i[101] : number +>i : { ...Indexed; b: number; [n: string]: number; } >101 : 101 -s = i.b; ->s = i.b : string ->s : string ->i.b : string ->i : { ...Indexed; b: string; [n: number]: string; } ->b : string +n = i.b; +>n = i.b : number +>n : number +>i.b : number +>i : { ...Indexed; b: number; [n: string]: number; } +>b : number + +interface Indexed2 { +>Indexed2 : Indexed2 + + [n: string]: boolean; +>n : string + + c: boolean; +>c : boolean +} +let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; +>ii : { ...Indexed; ...Indexed2; b: boolean; d: number; [x: string]: number | boolean; } +>Indexed : Indexed +>Indexed2 : Indexed2 +>b : boolean +>d : number + +let nb: number | boolean = ii[1001]; +>nb : number | boolean +>ii[1001] : number | boolean +>ii : { ...Indexed; ...Indexed2; b: boolean; d: number; [x: string]: number | boolean; } +>1001 : 1001 diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts index 11ba545008504..d6f9f511c7b9e 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -6,9 +6,15 @@ let c: { ...C, b: string, c?: string, [n: number]: string }; let n: number = c.a; let s: string = c[12]; interface Indexed { - [n: number]: string; - a: boolean; + [n: string]: number; + a: number; +} +let i: { ...Indexed, b: number }; +n = i[101]; +n = i.b; +interface Indexed2 { + [n: string]: boolean; + c: boolean; } -let i: { ...Indexed, b: string }; -s = i[101]; -s = i.b; +let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; +let nb: number | boolean = ii[1001]; From 7e7a26a3581c223f57f161dbc8f71ed4ac856590 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 27 Sep 2016 16:15:52 -0700 Subject: [PATCH 14/85] Spreads w/a single type parameter assignable to that type parameter --- src/compiler/checker.ts | 47 ++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e1e7cce4df41c..209598259ebc5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2321,8 +2321,6 @@ namespace ts { printFollowingPunctuation = true; } } - // TODO: Only print if this is directly on the type -- not on the subtype somewhere. - // (This is not crucial, though, since the extra info *might* be nice.) const resolved = resolveStructuredTypeMembers(type); writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword); writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword); @@ -6656,23 +6654,42 @@ namespace ts { } } - if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { - const sourceParameters = filter((source as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); - const targetParameters = filter((target as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); - if (sourceParameters.length !== targetParameters.length) { - reportRelationError(headMessage, source, target); - return Ternary.False; + if (source.flags & TypeFlags.Spread) { + if (target.flags & TypeFlags.TypeParameter) { + let hasTypeParameter = false; + let typeParametersAreEqual = true; + for (const t of (source as SpreadType).types) { + if (t.flags & TypeFlags.TypeParameter) { + hasTypeParameter = true; + if (t !== target) { + typeParametersAreEqual = false; + break; + } + } + } + if (hasTypeParameter && typeParametersAreEqual) { + errorInfo = saveErrorInfo; + return Ternary.True; + } } - for (let i = 0; i < sourceParameters.length; i++) { - if (sourceParameters[i].symbol !== targetParameters[i].symbol) { + else if (target.flags & TypeFlags.Spread) { + const sourceParameters = filter((source as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); + const targetParameters = filter((target as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); + if (sourceParameters.length !== targetParameters.length) { reportRelationError(headMessage, source, target); return Ternary.False; } - } - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; - if (result = objectTypeRelatedTo(source, source, target, reportStructuralErrors)) { - errorInfo = saveErrorInfo; - return result; + for (let i = 0; i < sourceParameters.length; i++) { + if (sourceParameters[i].symbol !== targetParameters[i].symbol) { + reportRelationError(headMessage, source, target); + return Ternary.False; + } + } + const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; + if (result = objectTypeRelatedTo(source, source, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } } } From 0f773c5673d85633d321fb4cb5cbed94739d3c78 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 27 Sep 2016 16:17:14 -0700 Subject: [PATCH 15/85] Add object spread scenario tests --- .../reference/objectSpreadScenarios.js | 45 ++++++++ .../reference/objectSpreadScenarios.symbols | 84 ++++++++++++++ .../reference/objectSpreadScenarios.types | 106 ++++++++++++++++++ .../types/spread/objectSpreadScenarios.ts | 17 +++ 4 files changed, 252 insertions(+) create mode 100644 tests/baselines/reference/objectSpreadScenarios.js create mode 100644 tests/baselines/reference/objectSpreadScenarios.symbols create mode 100644 tests/baselines/reference/objectSpreadScenarios.types create mode 100644 tests/cases/conformance/types/spread/objectSpreadScenarios.ts diff --git a/tests/baselines/reference/objectSpreadScenarios.js b/tests/baselines/reference/objectSpreadScenarios.js new file mode 100644 index 0000000000000..ae0e2f6c425ef --- /dev/null +++ b/tests/baselines/reference/objectSpreadScenarios.js @@ -0,0 +1,45 @@ +//// [objectSpreadScenarios.ts] +interface A1 { a: boolean } +interface B1 { b: number }; +function override(initial: U, override: U): U { + return { ...initial, ...override }; +} +function update(this: { u: U }, override: U): void { + this.u = { ...this.u, ...override }; +} +function mixin(one: T, two: U): { ...T, ...U } { + return { ...one, ...two }; +} +let a1: A1 = { a: true }; +let b1: B1 = { b: 101 }; +a1 = override(a1, { a: false }); +let host = { u: a1, update }; +host.update({ a: false }); +let mixed = mixin(a1, b1); + + +//// [objectSpreadScenarios.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +; +function override(initial, override) { + return __assign({}, initial, override); +} +function update(override) { + this.u = __assign({}, this.u, override); +} +function mixin(one, two) { + return __assign({}, one, two); +} +var a1 = { a: true }; +var b1 = { b: 101 }; +a1 = override(a1, { a: false }); +var host = { u: a1, update: update }; +host.update({ a: false }); +var mixed = mixin(a1, b1); diff --git a/tests/baselines/reference/objectSpreadScenarios.symbols b/tests/baselines/reference/objectSpreadScenarios.symbols new file mode 100644 index 0000000000000..c8c18ca1e2f5b --- /dev/null +++ b/tests/baselines/reference/objectSpreadScenarios.symbols @@ -0,0 +1,84 @@ +=== tests/cases/conformance/types/spread/objectSpreadScenarios.ts === +interface A1 { a: boolean } +>A1 : Symbol(A1, Decl(objectSpreadScenarios.ts, 0, 0)) +>a : Symbol(A1.a, Decl(objectSpreadScenarios.ts, 0, 14)) + +interface B1 { b: number }; +>B1 : Symbol(B1, Decl(objectSpreadScenarios.ts, 0, 27)) +>b : Symbol(B1.b, Decl(objectSpreadScenarios.ts, 1, 14)) + +function override(initial: U, override: U): U { +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 1, 27)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) +>initial : Symbol(initial, Decl(objectSpreadScenarios.ts, 2, 21)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 2, 32)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) + + return { ...initial, ...override }; +} +function update(this: { u: U }, override: U): void { +>update : Symbol(update, Decl(objectSpreadScenarios.ts, 4, 1)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) +>this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19)) +>u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 34)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) + + this.u = { ...this.u, ...override }; +>this.u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) +>this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19)) +>u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) +>this.u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) +>this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19)) +>u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) +} +function mixin(one: T, two: U): { ...T, ...U } { +>mixin : Symbol(mixin, Decl(objectSpreadScenarios.ts, 7, 1)) +>T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17)) +>one : Symbol(one, Decl(objectSpreadScenarios.ts, 8, 21)) +>T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15)) +>two : Symbol(two, Decl(objectSpreadScenarios.ts, 8, 28)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17)) +>T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17)) + + return { ...one, ...two }; +} +let a1: A1 = { a: true }; +>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3)) +>A1 : Symbol(A1, Decl(objectSpreadScenarios.ts, 0, 0)) +>a : Symbol(a, Decl(objectSpreadScenarios.ts, 11, 14)) + +let b1: B1 = { b: 101 }; +>b1 : Symbol(b1, Decl(objectSpreadScenarios.ts, 12, 3)) +>B1 : Symbol(B1, Decl(objectSpreadScenarios.ts, 0, 27)) +>b : Symbol(b, Decl(objectSpreadScenarios.ts, 12, 14)) + +a1 = override(a1, { a: false }); +>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 1, 27)) +>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3)) +>a : Symbol(a, Decl(objectSpreadScenarios.ts, 13, 19)) + +let host = { u: a1, update }; +>host : Symbol(host, Decl(objectSpreadScenarios.ts, 14, 3)) +>u : Symbol(u, Decl(objectSpreadScenarios.ts, 14, 12)) +>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3)) +>update : Symbol(update, Decl(objectSpreadScenarios.ts, 14, 19)) + +host.update({ a: false }); +>host.update : Symbol(update, Decl(objectSpreadScenarios.ts, 14, 19)) +>host : Symbol(host, Decl(objectSpreadScenarios.ts, 14, 3)) +>update : Symbol(update, Decl(objectSpreadScenarios.ts, 14, 19)) +>a : Symbol(a, Decl(objectSpreadScenarios.ts, 15, 13)) + +let mixed = mixin(a1, b1); +>mixed : Symbol(mixed, Decl(objectSpreadScenarios.ts, 16, 3)) +>mixin : Symbol(mixin, Decl(objectSpreadScenarios.ts, 7, 1)) +>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3)) +>b1 : Symbol(b1, Decl(objectSpreadScenarios.ts, 12, 3)) + diff --git a/tests/baselines/reference/objectSpreadScenarios.types b/tests/baselines/reference/objectSpreadScenarios.types new file mode 100644 index 0000000000000..eebe08a2aafe7 --- /dev/null +++ b/tests/baselines/reference/objectSpreadScenarios.types @@ -0,0 +1,106 @@ +=== tests/cases/conformance/types/spread/objectSpreadScenarios.ts === +interface A1 { a: boolean } +>A1 : A1 +>a : boolean + +interface B1 { b: number }; +>B1 : B1 +>b : number + +function override(initial: U, override: U): U { +>override : (initial: U, override: U) => U +>U : U +>initial : U +>U : U +>override : U +>U : U +>U : U + + return { ...initial, ...override }; +>{ ...initial, ...override } : { ...U; ...U } +>initial : any +>override : any +} +function update(this: { u: U }, override: U): void { +>update : (this: { u: U; }, override: U) => void +>U : U +>this : { u: U; } +>u : U +>U : U +>override : U +>U : U + + this.u = { ...this.u, ...override }; +>this.u = { ...this.u, ...override } : { ...U; ...U } +>this.u : U +>this : { u: U; } +>u : U +>{ ...this.u, ...override } : { ...U; ...U } +>this.u : U +>this : { u: U; } +>u : U +>override : any +} +function mixin(one: T, two: U): { ...T, ...U } { +>mixin : (one: T, two: U) => { ...T; ...U } +>T : T +>U : U +>one : T +>T : T +>two : U +>U : U +>T : T +>U : U + + return { ...one, ...two }; +>{ ...one, ...two } : { ...T; ...U } +>one : any +>two : any +} +let a1: A1 = { a: true }; +>a1 : A1 +>A1 : A1 +>{ a: true } : { a: true; } +>a : boolean +>true : true + +let b1: B1 = { b: 101 }; +>b1 : B1 +>B1 : B1 +>{ b: 101 } : { b: number; } +>b : number +>101 : 101 + +a1 = override(a1, { a: false }); +>a1 = override(a1, { a: false }) : A1 +>a1 : A1 +>override(a1, { a: false }) : A1 +>override : (initial: U, override: U) => U +>a1 : A1 +>{ a: false } : { a: false; } +>a : boolean +>false : false + +let host = { u: a1, update }; +>host : { u: A1; update: (this: { u: U; }, override: U) => void; } +>{ u: a1, update } : { u: A1; update: (this: { u: U; }, override: U) => void; } +>u : A1 +>a1 : A1 +>update : (this: { u: U; }, override: U) => void + +host.update({ a: false }); +>host.update({ a: false }) : void +>host.update : (this: { u: U; }, override: U) => void +>host : { u: A1; update: (this: { u: U; }, override: U) => void; } +>update : (this: { u: U; }, override: U) => void +>{ a: false } : { a: false; } +>a : boolean +>false : false + +let mixed = mixin(a1, b1); +>mixed : { ...A1; ...B1 } +>mixin(a1, b1) : { ...A1; ...B1 } +>mixin : (one: T, two: U) => { ...T; ...U } +>a1 : A1 +>b1 : B1 + diff --git a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts new file mode 100644 index 0000000000000..2f944ddb7966e --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts @@ -0,0 +1,17 @@ +interface A1 { a: boolean } +interface B1 { b: number }; +function override(initial: U, override: U): U { + return { ...initial, ...override }; +} +function update(this: { u: U }, override: U): void { + this.u = { ...this.u, ...override }; +} +function mixin(one: T, two: U): { ...T, ...U } { + return { ...one, ...two }; +} +let a1: A1 = { a: true }; +let b1: B1 = { b: 101 }; +a1 = override(a1, { a: false }); +let host = { u: a1, update }; +host.update({ a: false }); +let mixed = mixin(a1, b1); From 62c5bda3bbc1ee06d6ed0a575274da3159004f52 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 28 Sep 2016 14:14:53 -0700 Subject: [PATCH 16/85] isDeclaredProperty: Use optional-boolean idiom As elsewhere in the compiler code --- src/compiler/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0e120bd74f062..7a98efd007f8f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2536,7 +2536,7 @@ namespace ts { /* @internal */ export interface SpreadElementType extends ResolvedType { - isDeclaredProperty: boolean | undefined; + isDeclaredProperty?: boolean; } /* @internal */ From b9af986df1d4e277af6464033be98fbc666642d9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 3 Oct 2016 15:18:04 -0700 Subject: [PATCH 17/85] Update object spread scenarios test --- tests/baselines/reference/objectSpreadScenarios.js | 2 +- .../baselines/reference/objectSpreadScenarios.symbols | 3 ++- tests/baselines/reference/objectSpreadScenarios.types | 11 ++++++----- .../conformance/types/spread/objectSpreadScenarios.ts | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/objectSpreadScenarios.js b/tests/baselines/reference/objectSpreadScenarios.js index ae0e2f6c425ef..64739a2b298b0 100644 --- a/tests/baselines/reference/objectSpreadScenarios.js +++ b/tests/baselines/reference/objectSpreadScenarios.js @@ -1,7 +1,7 @@ //// [objectSpreadScenarios.ts] interface A1 { a: boolean } interface B1 { b: number }; -function override(initial: U, override: U): U { +function override(initial: U, override: U): { ...U, ...U } { return { ...initial, ...override }; } function update(this: { u: U }, override: U): void { diff --git a/tests/baselines/reference/objectSpreadScenarios.symbols b/tests/baselines/reference/objectSpreadScenarios.symbols index c8c18ca1e2f5b..784e340a10ce2 100644 --- a/tests/baselines/reference/objectSpreadScenarios.symbols +++ b/tests/baselines/reference/objectSpreadScenarios.symbols @@ -7,13 +7,14 @@ interface B1 { b: number }; >B1 : Symbol(B1, Decl(objectSpreadScenarios.ts, 0, 27)) >b : Symbol(B1.b, Decl(objectSpreadScenarios.ts, 1, 14)) -function override(initial: U, override: U): U { +function override(initial: U, override: U): { ...U, ...U } { >override : Symbol(override, Decl(objectSpreadScenarios.ts, 1, 27)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) >initial : Symbol(initial, Decl(objectSpreadScenarios.ts, 2, 21)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) >override : Symbol(override, Decl(objectSpreadScenarios.ts, 2, 32)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) +>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18)) return { ...initial, ...override }; diff --git a/tests/baselines/reference/objectSpreadScenarios.types b/tests/baselines/reference/objectSpreadScenarios.types index eebe08a2aafe7..5330029afe127 100644 --- a/tests/baselines/reference/objectSpreadScenarios.types +++ b/tests/baselines/reference/objectSpreadScenarios.types @@ -7,13 +7,14 @@ interface B1 { b: number }; >B1 : B1 >b : number -function override(initial: U, override: U): U { ->override : (initial: U, override: U) => U +function override(initial: U, override: U): { ...U, ...U } { +>override : (initial: U, override: U) => { ...U; ...U } >U : U >initial : U >U : U >override : U >U : U +>U : U >U : U return { ...initial, ...override }; @@ -72,10 +73,10 @@ let b1: B1 = { b: 101 }; >101 : 101 a1 = override(a1, { a: false }); ->a1 = override(a1, { a: false }) : A1 +>a1 = override(a1, { a: false }) : { ...A1; ...A1 } >a1 : A1 ->override(a1, { a: false }) : A1 ->override : (initial: U, override: U) => U +>override(a1, { a: false }) : { ...A1; ...A1 } +>override : (initial: U, override: U) => { ...U; ...U } >a1 : A1 >{ a: false } : { a: false; } >a : boolean diff --git a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts index 2f944ddb7966e..c80cffa44e701 100644 --- a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts +++ b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts @@ -1,6 +1,6 @@ interface A1 { a: boolean } interface B1 { b: number }; -function override(initial: U, override: U): U { +function override(initial: U, override: U): { ...U, ...U } { return { ...initial, ...override }; } function update(this: { u: U }, override: U): void { From 57850ecf1ae5cad2a81112b4152133a99c8b9837 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 3 Oct 2016 15:49:23 -0700 Subject: [PATCH 18/85] Add more generic assignability cases --- .../cases/conformance/types/spread/objectSpreadGeneric.ts | 7 +++++++ .../cases/conformance/types/spread/objectSpreadNegative.ts | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts index 552142004b70f..a6919ce814931 100644 --- a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts +++ b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts @@ -1,5 +1,12 @@ function f(t: T, u: U, v: V): void { let o: { ...T, ...U, ...V }; + let uu: { ...U, ...U}; + let u: { ...U }; + let u0: U; + uu = u; // ok, multiple spreads are equivalent to a single one + u = uu; // ok, multiple spreads are equivalent to a single one + u0 = u; // error, might be missing a ton of stuff + u = u0; // ok, type has at least all the properties of the spread const same: { ...T, ...U, ...V } = o; // ok const reversed: { ...V, ...U, ...T } = o; // error, reversed const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 4691e45a17df3..4d1cfbe398c32 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -47,3 +47,8 @@ callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions + +// { ...U } is not assignable to U +function override(initial: U, override: U): U { + return { ...initial, ...override }; +} From d770c568743d6cc7ae6e5c21387ba8d0bb9d419f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 7 Oct 2016 08:55:02 -0700 Subject: [PATCH 19/85] Switch spread types to a binary representation. This allows much easier creation of spread types. Spread type creation is now much smarter, and creates object types when possible. When it's not, it produces a spread type that simplifies its input into a standard structure for containing type parameters. The spread type is no longer related to union or intersection types. Spread types containing union and intersection types are not yet correctly handled. --- src/compiler/checker.ts | 387 +++++++++++++++++++++++----------------- src/compiler/types.ts | 21 ++- 2 files changed, 232 insertions(+), 176 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 44784c4ab2320..0e7266b223ccd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2310,33 +2310,40 @@ namespace ts { writePunctuation(writer, SyntaxKind.OpenBraceToken); writer.writeLine(); writer.increaseIndent(); - let printFollowingPunctuation = false; - for (const t of type.types) { - if (printFollowingPunctuation) { - writePunctuation(writer, SyntaxKind.SemicolonToken); - writer.writeLine(); - } - if (t.isDeclaredProperty) { - const saveInObjectTypeLiteral = inObjectTypeLiteral; - inObjectTypeLiteral = true; - writeObjectLiteralType(resolveStructuredTypeMembers(t)); - printFollowingPunctuation = false; - inObjectTypeLiteral = saveInObjectTypeLiteral; + + writeSpreadTypeWorker(type, /*atEnd*/true, type.symbol); + + writer.decreaseIndent(); + writePunctuation(writer, SyntaxKind.CloseBraceToken); + } + + function writeSpreadTypeWorker(type: SpreadType, atEnd: boolean, container: Symbol): void { + if (type.left.flags & TypeFlags.Spread) { + writeSpreadTypeWorker(type.left as SpreadType, /*atEnd*/false, container); + } + else { + const saveInObjectTypeLiteral = inObjectTypeLiteral; + inObjectTypeLiteral = true; + writeObjectLiteralType(resolveStructuredTypeMembers(type.left)); + inObjectTypeLiteral = saveInObjectTypeLiteral; + } + if (type.right.symbol === container) { + const saveInObjectTypeLiteral = inObjectTypeLiteral; + inObjectTypeLiteral = true; + writeObjectLiteralType(resolveStructuredTypeMembers(type.right)); + inObjectTypeLiteral = saveInObjectTypeLiteral; + } + else { + writePunctuation(writer, SyntaxKind.DotDotDotToken); + writeType(type.right, TypeFormatFlags.None); + if (atEnd) { + writeSpace(writer); } else { - writePunctuation(writer, SyntaxKind.DotDotDotToken); - writeType(t, TypeFormatFlags.None); - printFollowingPunctuation = true; + writePunctuation(writer, SyntaxKind.SemicolonToken); + writer.writeLine(); } } - const resolved = resolveStructuredTypeMembers(type); - writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword); - writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword); - writer.decreaseIndent(); - if (printFollowingPunctuation) { - writeSpace(writer); - } - writePunctuation(writer, SyntaxKind.CloseBraceToken); } function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) { @@ -3522,6 +3529,9 @@ namespace ts { if (symbol.flags & SymbolFlags.Instantiated) { return getTypeOfInstantiatedSymbol(symbol); } + if (symbol.flags & SymbolFlags.SyntheticProperty && symbol.syntheticKind === SyntheticSymbolKind.Spread) { + return getTypeOfSpreadProperty(symbol); + } if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { return getTypeOfVariableOrParameterOrProperty(symbol); } @@ -3540,6 +3550,15 @@ namespace ts { return unknownType; } + function getTypeOfSpreadProperty(symbol: Symbol) { + const links = getSymbolLinks(symbol); + if (!links.type) { + links.type = getUnionType([getTypeOfSymbol(links.leftSpread), getTypeOfSymbol(links.rightSpread)]); + } + return links.type; + + } + function getTargetType(type: ObjectType): Type { return type.flags & TypeFlags.Reference ? (type).target : type; } @@ -4340,21 +4359,6 @@ namespace ts { setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); } - function resolveSpreadTypeMembers(type: SpreadType) { - // The members and properties collections are empty for spread types. To get all properties of an - // spread type use getPropertiesOfType. - let stringIndexInfo: IndexInfo = getIndexInfoOfSymbol(type.symbol, IndexKind.String); - let numberIndexInfo: IndexInfo = getIndexInfoOfSymbol(type.symbol, IndexKind.Number); - for (let i = type.types.length - 1; i > -1; i--) { - const t = type.types[i]; - if (!t.isDeclaredProperty) { - stringIndexInfo = unionIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); - numberIndexInfo = unionIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); - } - } - setObjectTypeMembers(type, emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); - } - function resolveAnonymousTypeMembers(type: AnonymousType) { const symbol = type.symbol; if (type.target) { @@ -4421,9 +4425,6 @@ namespace ts { else if (type.flags & TypeFlags.Intersection) { resolveIntersectionTypeMembers(type); } - else if (type.flags & TypeFlags.Spread) { - resolveSpreadTypeMembers(type); - } } return type; } @@ -4433,9 +4434,6 @@ namespace ts { if (type.flags & TypeFlags.ObjectType) { return resolveStructuredTypeMembers(type).properties; } - if (type.flags & TypeFlags.Spread) { - return getPropertiesOfType(type); - } return emptyArray; } @@ -4451,11 +4449,10 @@ namespace ts { } } - function getPropertiesOfUnionOrIntersectionOrSpreadType(type: TypeOperatorType): Symbol[] { - const getProperty = type.flags & TypeFlags.Spread ? getPropertyOfSpreadType : getUnionOrIntersectionProperty; + function getPropertiesOfUnionOrIntersectionType(type: TypeOperatorType): Symbol[] { for (const current of type.types) { for (const prop of getPropertiesOfType(current)) { - getProperty(type, prop.name); + getUnionOrIntersectionProperty(type, prop.name); } // The properties of a union type are those that are present in all constituent types, so // we only need to check the properties of the first type @@ -4480,8 +4477,10 @@ namespace ts { function getPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); - return type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.Spread) ? getPropertiesOfUnionOrIntersectionOrSpreadType(type) : - getPropertiesOfObjectType(type); + if (type.flags & TypeFlags.UnionOrIntersection) { + return getPropertiesOfUnionOrIntersectionType(type); + } + return getPropertiesOfObjectType(type); } /** @@ -4499,6 +4498,10 @@ namespace ts { return type.resolvedApparentType; } + function getApparentTypeOfSpread(type: SpreadType) { + return getSpreadType([getApparentType(type.left), getApparentType(type.right)], type.symbol, undefined, undefined); + } + /** * For a type parameter, return the base constraint of the type parameter. For the string, number, * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the @@ -4507,7 +4510,10 @@ namespace ts { function getApparentType(type: Type): Type { if (type.flags & TypeFlags.TypeParameter) { type = getApparentTypeOfTypeParameter(type); - } + } + if (type.flags & TypeFlags.Spread) { + type = getApparentTypeOfSpread(type as SpreadType); + } if (type.flags & TypeFlags.StringLike) { type = globalStringType; } @@ -4585,6 +4591,7 @@ namespace ts { propTypes.push(type); } const result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | flags, name); + result.syntheticKind === SyntheticSymbolKind.UnionOrIntersection; result.containingType = containingType; result.hasNonUniformType = hasNonUniformType; result.isPartial = isPartial; @@ -4614,61 +4621,6 @@ namespace ts { return property; } - function createSpreadProperty(containingType: SpreadType, name: string): Symbol { - const types = containingType.types; - return createUnionOrIntersectionOrSpreadPropertySymbol(containingType, name, () => { - let props: Symbol[]; - // Result is readonly if any source is readonly - let isReadonly = false; - // Result is optional if all sources are optional - let commonFlags = SymbolFlags.Optional; - for (let i = types.length - 1; i > -1; i--) { - const type = getApparentType(types[i]); - if (type !== unknownType) { - const prop = getPropertyOfType(type, name); - if (prop) { - if (prop.flags & SymbolFlags.Method && !types[i].isDeclaredProperty || - prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor)) { - // skip non-object-literal methods and set-only properties and keep looking - continue; - } - if (!props) { - props = [prop]; - } - else if (!contains(props, prop)) { - props.unshift(prop); - } - if (isReadonlySymbol(prop)) { - isReadonly = true; - } - if (getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) { - // return immediately because even if prop is optional, it would make the unioned spread property private - return [undefined, false, false, 0]; - } - if (!(prop.flags & SymbolFlags.Optional)) { - // Reset extraFlags to None since we found a non-optional property - commonFlags = SymbolFlags.None; - break; - } - } - } - } - return [props, isReadonly, /*isPartial*/ false, commonFlags]; - }); - } - - function getPropertyOfSpreadType(type: TypeOperatorType, name: string): Symbol { - const properties = type.resolvedProperties || (type.resolvedProperties = createMap()); - let property = properties[name]; - if (!property) { - property = createSpreadProperty(type as SpreadType, name); - if (property) { - properties[name] = property; - } - } - return property; - } - function getPropertyOfUnionOrIntersectionType(type: TypeOperatorType, name: string): Symbol { const property = getUnionOrIntersectionProperty(type, name); // We need to filter out partial properties in union types @@ -4702,9 +4654,6 @@ namespace ts { if (type.flags & TypeFlags.UnionOrIntersection) { return getPropertyOfUnionOrIntersectionType(type, name); } - if (type.flags & TypeFlags.Spread) { - return getPropertyOfSpreadType(type, name); - } return undefined; } @@ -5775,16 +5724,14 @@ namespace ts { let type: ObjectType; if (isSpread) { let members: Map; - const spreads: SpreadElementType[] = []; + const spreads: Type[] = []; for (const member of (node as TypeLiteralNode).members) { if (member.kind === SyntaxKind.SpreadTypeElement) { if (members) { - const t = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined) as SpreadElementType; - t.isDeclaredProperty = true; - spreads.push(t); + spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, undefined, undefined)); members = undefined; } - spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type) as SpreadElementType); + spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type)); } else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature && @@ -5803,11 +5750,9 @@ namespace ts { } } if (members) { - const t = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined) as SpreadElementType; - t.isDeclaredProperty = true; - spreads.push(t); + spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, undefined, undefined)); } - return getSpreadType(spreads, node.symbol); + return getSpreadType(spreads, node.symbol, aliasSymbol, aliasTypeArguments); } else { type = createObjectType(TypeFlags.Anonymous, node.symbol); @@ -5819,13 +5764,94 @@ namespace ts { return links.resolvedType; } - function getSpreadType(types: SpreadElementType[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getSpreadType(types: Type[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + if (types.length === 0) { + return emptyObjectType; + } const id = getTypeListId(types); if (id in spreadTypes) { return spreadTypes[id]; } + const right = types.pop(); + if (right.flags & TypeFlags.Spread) { + // spread is right associative and associativity applies, so transform + // (T ... U) ... V to T ... (U ... V) + const rspread = right as SpreadType; + if (rspread.left !== emptyObjectType) { + types.push(rspread.left); + } + types.push(rspread.right); + return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); + } + const atBeginning = types.length === 0; + const left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); + if (right.flags & (TypeFlags.Null | TypeFlags.Undefined)) { + return left; + } + if (right.flags & TypeFlags.TypeParameter && + left.flags & TypeFlags.Spread && + (left as SpreadType).right.flags & TypeFlags.TypeParameter && + right.symbol === (left as SpreadType).right.symbol) { + // for types like T ... T, just return ... T + return left; + } + if (!(right.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.TypeParameter | TypeFlags.Spread)) + && !(left.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.TypeParameter | TypeFlags.Spread))) { + const members = createMap(); + const skippedPrivateMembers = createMap(); + let stringIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); + let numberIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); + if (atBeginning) { + // only get index info from the entire type once per spread type + stringIndexInfo = unionIndexInfos(stringIndexInfo, getIndexInfoOfSymbol(symbol, IndexKind.String)); + numberIndexInfo = unionIndexInfos(numberIndexInfo, getIndexInfoOfSymbol(symbol, IndexKind.Number)); + } + const isFromSpread = right.symbol !== symbol; + for (const rightProp of getPropertiesOfType(right)) { + if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { + skippedPrivateMembers[rightProp.name] = true; + } + else if (!(rightProp.flags & SymbolFlags.Method && isFromSpread) && + !(rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor))) { + // skip methods from spreads and accessors with setters but no getters + members[rightProp.name] = rightProp; + } + } + for (const leftProp of getPropertiesOfType(left)) { + if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor) + || leftProp.name in skippedPrivateMembers) { + // skip set-only properties (methods have already been skipped by the recursive call to getSpreadType) + continue; + } + if (leftProp.name in members) { + const rightProp = members[leftProp.name]; + if (rightProp.flags & SymbolFlags.Optional) { + const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations); + const flags = SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | (leftProp.flags & SymbolFlags.Optional); + const result = createSymbol(flags, leftProp.name); + result.syntheticKind = SyntheticSymbolKind.Spread; + result.leftSpread = leftProp; + result.rightSpread = rightProp; + result.declarations = declarations; + if (declarations.length) { + result.valueDeclaration = declarations[0]; + } + result.isReadonly = isReadonlySymbol(rightProp) || isReadonlySymbol(leftProp); + members[leftProp.name] = result; + } + } + else { + members[leftProp.name] = leftProp; + } + } + return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + } + // one side is a type parameter (TODO: Or union or intersection) const spread = spreadTypes[id] = createObjectType(TypeFlags.Spread, symbol) as SpreadType; - spread.types = filter(types, t => !(t.flags & (TypeFlags.Null | TypeFlags.Undefined))); + Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.ObjectType))); + Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.ObjectType))); + spread.left = left as SpreadType | ResolvedType; + spread.right = right as TypeParameter | ResolvedType; spread.aliasSymbol = aliasSymbol; spread.aliasTypeArguments = aliasTypeArguments; return spread; @@ -6238,7 +6264,8 @@ namespace ts { return getIntersectionType(instantiateList((type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes); } if (type.flags & TypeFlags.Spread) { - return getSpreadType(instantiateList((type as SpreadType).types, mapper, instantiateType) as SpreadElementType[], type.symbol, type.aliasSymbol, mapper.targetTypes); + const spread = type as SpreadType; + return getSpreadType([instantiateType(spread.left, mapper), instantiateType(spread.right, mapper)], type.symbol, type.aliasSymbol, mapper.targetTypes); } } return type; @@ -6776,38 +6803,15 @@ namespace ts { } if (source.flags & TypeFlags.Spread) { - if (target.flags & TypeFlags.TypeParameter) { - let hasTypeParameter = false; - let typeParametersAreEqual = true; - for (const t of (source as SpreadType).types) { - if (t.flags & TypeFlags.TypeParameter) { - hasTypeParameter = true; - if (t !== target) { - typeParametersAreEqual = false; - break; - } - } - } - if (hasTypeParameter && typeParametersAreEqual) { - errorInfo = saveErrorInfo; - return Ternary.True; - } - } - else if (target.flags & TypeFlags.Spread) { - const sourceParameters = filter((source as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); - const targetParameters = filter((target as SpreadType).types, t => !!(t.flags & TypeFlags.TypeParameter)); - if (sourceParameters.length !== targetParameters.length) { + // you only see this for spreads with type parameters (TODO: and unions/intersections) + if (target.flags & TypeFlags.Spread) { + if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType))) { reportRelationError(headMessage, source, target); return Ternary.False; } - for (let i = 0; i < sourceParameters.length; i++) { - if (sourceParameters[i].symbol !== targetParameters[i].symbol) { - reportRelationError(headMessage, source, target); - return Ternary.False; - } - } const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; - if (result = objectTypeRelatedTo(source, source, target, reportStructuralErrors)) { + const apparentSource = getApparentType(source); + if (result = objectTypeRelatedTo(apparentSource, source, getApparentType(target), reportStructuralErrors)) { errorInfo = saveErrorInfo; return result; } @@ -6815,6 +6819,13 @@ namespace ts { } if (source.flags & TypeFlags.TypeParameter) { + if (target.flags & TypeFlags.Spread) { + // T is assignable to ...T + if (source.symbol === (target as SpreadType).right.symbol + && (target as SpreadType).left === emptyObjectType) { + return Ternary.True; + } + } let constraint = getConstraintOfTypeParameter(source); if (!constraint || constraint.flags & TypeFlags.Any) { @@ -6844,7 +6855,7 @@ namespace ts { // In a check of the form X = A & B, we will have previously checked if A relates to X or B relates // to X. Failing both of those we want to check if the aggregation of A and B's members structurally // relates to X. Thus, we include intersection types on the source side here. - if (apparentSource.flags & (TypeFlags.ObjectType | TypeFlags.Intersection | TypeFlags.Spread) && target.flags & TypeFlags.ObjectType) { + if (apparentSource.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) { // Report structural errors only if we haven't reported any errors yet const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !(source.flags & TypeFlags.Primitive); if (result = objectTypeRelatedTo(apparentSource, source, target, reportStructuralErrors)) { @@ -6866,6 +6877,43 @@ namespace ts { return Ternary.False; } + function spreadTypeRelatedTo(source: SpreadType, target: SpreadType): boolean { + // (Spread ... Object) | (Spread | Object ... TypeParameter) + // in other words, if the right side is Object, then the left side must be a Spread. + if (source.right.flags & TypeFlags.ObjectType && + target.right.flags & TypeFlags.ObjectType) { + return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); + } + if (source.right.flags & TypeFlags.ObjectType) { + /// target.right is TypeParameter, skip source.right, but keep looking at target + return spreadTypeRelatedTo(source.left as SpreadType, target); + } + if (target.right.flags & TypeFlags.ObjectType) { + /// source.right is TypeParameter, skip target.right, but keep looking at source + return spreadTypeRelatedTo(source, target.left as SpreadType); + } + else { + // both rights are type parameters, so they must be identical + // and both lefts must be the same: + // if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed + if (target.right.symbol !== source.right.symbol) { + return false; + } + if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) { + return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); + } + else if (source.left.flags & TypeFlags.ObjectType && target.left.flags & TypeFlags.ObjectType) { + return true; // let structural compatibility figure it out later + } + else { + // one side is a spread, so it must have more type parameters, which will not be matched by the other side + // return false immediately instead of descending to find this out. + return false; + } + } + + } + function isIdenticalTo(source: Type, target: Type): Ternary { let result: Ternary; if (source.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { @@ -10558,7 +10606,7 @@ namespace ts { let propertiesTable = createMap(); let propertiesArray: Symbol[] = []; - const spreads: SpreadElementType[] = []; + const spreads: Type[] = []; const contextualType = getApparentTypeOfContextualType(node); const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); @@ -10631,15 +10679,13 @@ namespace ts { } else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { if (propertiesArray.length > 0) { - const t = createObjectLiteralType() as SpreadElementType; - t.isDeclaredProperty = true; - spreads.push(t); + spreads.push(createObjectLiteralType()); propertiesArray = []; propertiesTable = createMap(); hasComputedStringProperty = false; hasComputedNumberProperty = false; } - spreads.push(checkExpression((memberDecl as SpreadElementExpression).expression) as SpreadElementType); + spreads.push(checkExpression((memberDecl as SpreadElementExpression).expression)); continue; } else { @@ -10683,17 +10729,16 @@ namespace ts { if (spreads.length > 0) { if (propertiesArray.length > 0) { - const t = createObjectLiteralType() as SpreadElementType; - t.isDeclaredProperty = true; - spreads.push(t); + spreads.push(createObjectLiteralType()); } const propagatedFlags = getPropagatingFlagsOfTypes(spreads, /*excludeKinds*/ TypeFlags.Nullable); - const spread = getSpreadType(spreads, node.symbol); + const spread = getSpreadType(spreads, node.symbol, undefined, undefined); spread.flags |= propagatedFlags; return spread; } return createObjectLiteralType(); + function createObjectLiteralType() { const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined; const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined; @@ -10708,7 +10753,6 @@ namespace ts { } return result; } - } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { @@ -18943,15 +18987,22 @@ namespace ts { function getRootSymbols(symbol: Symbol): Symbol[] { if (symbol.flags & SymbolFlags.SyntheticProperty) { - const symbols: Symbol[] = []; - const name = symbol.name; - forEach(getSymbolLinks(symbol).containingType.types, t => { - const symbol = getPropertyOfType(t, name); - if (symbol) { - symbols.push(symbol); - } - }); - return symbols; + if (symbol.syntheticKind === SyntheticSymbolKind.Spread) { + const name = symbol.name; + const links = getSymbolLinks(symbol); + return [links.leftSpread, links.rightSpread]; + } + else { + const symbols: Symbol[] = []; + const name = symbol.name; + forEach(getSymbolLinks(symbol).containingType.types, t => { + const symbol = getPropertyOfType(t, name); + if (symbol) { + symbols.push(symbol); + } + }); + return symbols; + } } else if (symbol.flags & SymbolFlags.Transient) { let target: Symbol; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 685b94f9d8e06..75aaf03f08b19 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2318,6 +2318,12 @@ namespace ts { CannotBeNamed } + /* @internal */ + export const enum SyntheticSymbolKind { + UnionOrIntersection, + Spread + } + export const enum TypePredicateKind { This, Identifier @@ -2442,7 +2448,7 @@ namespace ts { Merged = 0x02000000, // Merged symbol (created during program binding) Transient = 0x04000000, // Transient symbol (created during type check) Prototype = 0x08000000, // Prototype property (no source representation) - SyntheticProperty = 0x10000000, // Property in union or intersection type + SyntheticProperty = 0x10000000, // Property in union, intersection or spread type Optional = 0x20000000, // Optional property ExportStar = 0x40000000, // Export * declaration @@ -2517,6 +2523,7 @@ namespace ts { /* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments + /* @internal */ syntheticKind?: SyntheticSymbolKind; // Synthetic symbols are either spread or union/intersection } /* @internal */ @@ -2530,6 +2537,8 @@ namespace ts { mapper?: TypeMapper; // Type mapper for instantiation alias referenced?: boolean; // True if alias symbol has been referenced as a value containingType?: TypeOperatorType; // Containing union or intersection type for synthetic property + leftSpread?: Symbol; // Left source for synthetic spread property + rightSpread?: Symbol; // Right source for synthetic spread property hasNonUniformType?: boolean; // True if constituents have non-uniform types isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents isDiscriminantProperty?: boolean; // True if discriminant synthetic property @@ -2759,13 +2768,9 @@ namespace ts { export interface IntersectionType extends TypeOperatorType { } /* @internal */ - export interface SpreadType extends TypeOperatorType { - types: SpreadElementType[]; // Constituent types - } - - /* @internal */ - export interface SpreadElementType extends ResolvedType { - isDeclaredProperty?: boolean; + export interface SpreadType extends Type { + left: SpreadType | ResolvedType; + right: TypeParameter | ResolvedType; } /* @internal */ From 98720755bdb0f6858905d32ed149a2a85cafe7b2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 7 Oct 2016 08:58:50 -0700 Subject: [PATCH 20/85] Spread type:new assignability+simplification tests --- .../conformance/types/spread/objectSpreadGeneric.ts | 13 ++++++------- .../types/spread/objectSpreadNegative.ts | 7 +++---- .../types/spread/objectSpreadScenarios.ts | 2 +- tests/cases/fourslash/findAllRefsForObjectSpread.ts | 2 +- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts index a6919ce814931..e3bd1ab7bb32a 100644 --- a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts +++ b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts @@ -1,13 +1,12 @@ function f(t: T, u: U, v: V): void { let o: { ...T, ...U, ...V }; - let uu: { ...U, ...U}; - let u: { ...U }; - let u0: U; - uu = u; // ok, multiple spreads are equivalent to a single one - u = uu; // ok, multiple spreads are equivalent to a single one - u0 = u; // error, might be missing a ton of stuff - u = u0; // ok, type has at least all the properties of the spread + let uus: { ...U, ...U}; + let us: { ...U }; const same: { ...T, ...U, ...V } = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff const reversed: { ...V, ...U, ...T } = o; // error, reversed const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed const missingT: { ...U, ...V } = o; // error, missing T diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 4d1cfbe398c32..d492db4c638b9 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -8,10 +8,8 @@ class PrivateOptionalX { class PublicX { public x: number; } -let privateOptionalx: PrivateOptionalX; -let publicx: PublicX; -let o3 = { ...publicx, ...privateOptionalx }; -let sn: string | number = o3.x; // error, x is private +let o3: { ...PublicX, ...PrivateOptionalX }; +let sn: number = o3.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; @@ -46,6 +44,7 @@ let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: numb callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature +let publicx: PublicX; let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions // { ...U } is not assignable to U diff --git a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts index c80cffa44e701..1db930cb71c51 100644 --- a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts +++ b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts @@ -3,7 +3,7 @@ interface B1 { b: number }; function override(initial: U, override: U): { ...U, ...U } { return { ...initial, ...override }; } -function update(this: { u: U }, override: U): void { +function update(this: { u: { ...U } }, override: U): void { this.u = { ...this.u, ...override }; } function mixin(one: T, two: U): { ...T, ...U } { diff --git a/tests/cases/fourslash/findAllRefsForObjectSpread.ts b/tests/cases/fourslash/findAllRefsForObjectSpread.ts index fe0a7f9c20195..650324a5d8467 100644 --- a/tests/cases/fourslash/findAllRefsForObjectSpread.ts +++ b/tests/cases/fourslash/findAllRefsForObjectSpread.ts @@ -1,6 +1,6 @@ /// -////interface A1 { [|a|]: number }; +////interface A1 { [|a|]: string }; ////interface A2 { [|a|]?: number }; ////let a12: { ...A1, ...A2 }; ////a12.[|a|]; From df735795e53821575488dcc5d6cf95f1ef96b63a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 7 Oct 2016 08:59:46 -0700 Subject: [PATCH 21/85] Update baselines --- tests/baselines/reference/objectSpread.types | 72 +++++++++---------- .../reference/objectSpreadGeneric.errors.txt | 43 ++++++----- .../reference/objectSpreadGeneric.js | 12 ++++ .../objectSpreadIndexSignature.types | 16 ++--- .../reference/objectSpreadNegative.errors.txt | 67 +++++++++-------- .../reference/objectSpreadNegative.js | 21 ++++-- .../reference/objectSpreadScenarios.js | 2 +- .../reference/objectSpreadScenarios.symbols | 4 +- .../reference/objectSpreadScenarios.types | 50 ++++++------- ...ariableDeclarationInStrictMode1.errors.txt | 2 +- 10 files changed, 164 insertions(+), 125 deletions(-) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 1a053a22670c0..86d04eb4588be 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -31,7 +31,7 @@ let addAfter: { a: number, b: string, c: boolean } = >c : boolean { ...o, c: false } ->{ ...o, c: false } : { ...{ a: number; b: string; }; c: false; } +>{ ...o, c: false } : { c: false; a: number; b: string; } >o : any >c : boolean >false : false @@ -43,7 +43,7 @@ let addBefore: { a: number, b: string, c: boolean } = >c : boolean { c: false, ...o } ->{ c: false, ...o } : { c: false; ...{ a: number; b: string; } } +>{ c: false, ...o } : { a: number; b: string; c: false; } >c : boolean >false : false >o : any @@ -55,7 +55,7 @@ let ignore: { a: number, b: string } = >b : string { b: 'ignored', ...o } ->{ b: 'ignored', ...o } : { b: string; ...{ a: number; b: string; } } +>{ b: 'ignored', ...o } : { a: number; b: string; } >b : string >'ignored' : "ignored" >o : any @@ -66,7 +66,7 @@ let override: { a: number, b: string } = >b : string { ...o, b: 'override' } ->{ ...o, b: 'override' } : { ...{ a: number; b: string; }; b: string; } +>{ ...o, b: 'override' } : { b: string; a: number; } >o : any >b : string >'override' : "override" @@ -78,8 +78,8 @@ let nested: { a: number, b: boolean, c: string } = >c : string { ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } ->{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } : { ...{ a: number; ...{ b: boolean; c: string; } }; c: string; } ->{ a: 3, ...{ b: false, c: 'overriden' } } : { a: number; ...{ b: boolean; c: string; } } +>{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } : { c: string; b: boolean; a: number; } +>{ a: 3, ...{ b: false, c: 'overriden' } } : { b: boolean; c: string; a: number; } >a : number >3 : 3 >{ b: false, c: 'overriden' } : { b: boolean; c: string; } @@ -97,7 +97,7 @@ let combined: { a: number, b: string, c: boolean } = >c : boolean { ...o, ...o2 } ->{ ...o, ...o2 } : { ...{ a: number; b: string; }; ...{ b: string; c: boolean; } } +>{ ...o, ...o2 } : { b: string; c: boolean; a: number; } >o : any >o2 : any @@ -108,7 +108,7 @@ let combinedBefore: { a: number, b: string, c: boolean } = >c : boolean { b: 'ok', ...o, ...o2 } ->{ b: 'ok', ...o, ...o2 } : { b: string; ...{ a: number; b: string; }; ...{ b: string; c: boolean; } } +>{ b: 'ok', ...o, ...o2 } : { b: string; c: boolean; a: number; } >b : string >'ok' : "ok" >o : any @@ -121,7 +121,7 @@ let combinedMid: { a: number, b: string, c: boolean } = >c : boolean { ...o, b: 'ok', ...o2 } ->{ ...o, b: 'ok', ...o2 } : { ...{ a: number; b: string; }; b: string; ...{ b: string; c: boolean; } } +>{ ...o, b: 'ok', ...o2 } : { b: string; c: boolean; a: number; } >o : any >b : string >'ok' : "ok" @@ -134,7 +134,7 @@ let combinedAfter: { a: number, b: string, c: boolean } = >c : boolean { ...o, ...o2, b: 'ok' } ->{ ...o, ...o2, b: 'ok' } : { ...{ a: number; b: string; }; ...{ b: string; c: boolean; }; b: string; } +>{ ...o, ...o2, b: 'ok' } : { b: string; c: boolean; a: number; } >o : any >o2 : any >b : string @@ -148,8 +148,8 @@ let combinedNested: { a: number, b: boolean, c: string, d: string } = >d : string { ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } ->{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } : { ...{ a: number; ...{ b: boolean; c: string; } }; d: string; ...{ a: number; d: string; } } ->{ a: 4, ...{ b: false, c: 'overriden' } } : { a: number; ...{ b: boolean; c: string; } } +>{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } : { a: number; d: string; b: boolean; c: string; } +>{ a: 4, ...{ b: false, c: 'overriden' } } : { b: boolean; c: string; a: number; } >a : number >4 : 4 >{ b: false, c: 'overriden' } : { b: boolean; c: string; } @@ -172,8 +172,8 @@ let combinedNestedChangeType: { a: number, b: boolean, c: number } = >c : number { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } ->{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } : { ...{ a: number; ...{ b: boolean; c: string; } }; c: number; } ->{ a: 1, ...{ b: false, c: 'overriden' } } : { a: number; ...{ b: boolean; c: string; } } +>{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } : { c: number; b: boolean; a: number; } +>{ a: 1, ...{ b: false, c: 'overriden' } } : { b: boolean; c: string; a: number; } >a : number >1 : 1 >{ b: false, c: 'overriden' } : { b: boolean; c: string; } @@ -192,9 +192,9 @@ let propertyNested: { a: { a: number, b: string } } = >b : string { a: { ... o } } ->{ a: { ... o } } : { a: { ...{ a: number; b: string; } }; } ->a : { ...{ a: number; b: string; } } ->{ ... o } : { ...{ a: number; b: string; } } +>{ a: { ... o } } : { a: { a: number; b: string; }; } +>a : { a: number; b: string; } +>{ ... o } : { a: number; b: string; } >o : any // accessors don't copy the descriptor @@ -211,7 +211,7 @@ let getter: { a: number, c: number } = >c : number { ...op, c: 7 } ->{ ...op, c: 7 } : { ...{ readonly a: number; }; c: number; } +>{ ...op, c: 7 } : { c: number; readonly a: number; } >op : any >c : number >7 : 7 @@ -260,7 +260,7 @@ let c: C = new C() let spreadC: { p: number } = { ...c } >spreadC : { p: number; } >p : number ->{ ...c } : { ...C } +>{ ...c } : { p: number; } >c : any // own methods are enumerable @@ -268,7 +268,7 @@ let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } } >cplus : { p: number; plus(): void; } >p : number >plus : () => void ->{ ...c, plus() { return this.p + 1; } } : { ...C; plus(): any; } +>{ ...c, plus() { return this.p + 1; } } : { plus(): any; p: number; } >c : any >plus : () => any >this.p + 1 : any @@ -290,7 +290,7 @@ let changeTypeAfter: { a: string, b: string } = >b : string { ...o, a: 'wrong type?' } ->{ ...o, a: 'wrong type?' } : { ...{ a: number; b: string; }; a: string; } +>{ ...o, a: 'wrong type?' } : { a: string; b: string; } >o : any >a : string >'wrong type?' : "wrong type?" @@ -301,7 +301,7 @@ let changeTypeBefore: { a: number, b: string } = >b : string { a: 'wrong type?', ...o }; ->{ a: 'wrong type?', ...o } : { a: string; ...{ a: number; b: string; } } +>{ a: 'wrong type?', ...o } : { a: number; b: string; } >a : string >'wrong type?' : "wrong type?" >o : any @@ -312,7 +312,7 @@ let changeTypeBoth: { a: string, b: number } = >b : number { ...o, ...swap }; ->{ ...o, ...swap } : { ...{ a: number; b: string; }; ...{ a: string; b: number; } } +>{ ...o, ...swap } : { a: string; b: number; } >o : any >swap : any @@ -336,7 +336,7 @@ let optionalNumber: { sn?: number }; let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; >optionalUnionStops : { sn: string | number | boolean; } >sn : string | number | boolean ->{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { ...{ sn: boolean; }; ...{ sn: string; }; ...{ sn?: number; } } +>{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { sn: string | number; } >definiteBoolean : any >definiteString : any >optionalNumber : any @@ -344,7 +344,7 @@ let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; >optionalUnionDuplicates : { sn: string | number; } >sn : string | number ->{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { ...{ sn: boolean; }; ...{ sn: string; }; ...{ sn?: string; }; ...{ sn?: number; } } +>{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { sn: string | number; } >definiteBoolean : any >definiteString : any >optionalString : any @@ -353,7 +353,7 @@ let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ... let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; >allOptional : { sn?: string | number; } >sn : string | number ->{ ...optionalString, ...optionalNumber } : { ...{ sn?: string; }; ...{ sn?: number; } } +>{ ...optionalString, ...optionalNumber } : { sn?: string | number; } >optionalString : any >optionalNumber : any @@ -364,7 +364,7 @@ let computedFirst: { a: number, b: string, "before everything": number } = >b : string { ['before everything']: 12, ...o, b: 'yes' } ->{ ['before everything']: 12, ...o, b: 'yes' } : { ['before everything']: number; ...{ a: number; b: string; }; b: string; } +>{ ['before everything']: 12, ...o, b: 'yes' } : { b: string; a: number; ['before everything']: number; } >'before everything' : "before everything" >12 : 12 >o : any @@ -378,7 +378,7 @@ let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number >c : boolean { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { ...{ a: number; b: string; }; ['in the middle']: number; b: string; ...{ b: string; c: boolean; } } +>{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { b: string; c: boolean; ['in the middle']: number; a: number; } >o : any >'in the middle' : "in the middle" >13 : 13 @@ -392,7 +392,7 @@ let computedAfter: { a: number, b: string, "at the end": number } = >b : string { ...o, b: 'yeah', ['at the end']: 14 } ->{ ...o, b: 'yeah', ['at the end']: 14 } : { ...{ a: number; b: string; }; b: string; ['at the end']: number; } +>{ ...o, b: 'yeah', ['at the end']: 14 } : { b: string; ['at the end']: number; a: number; } >o : any >b : string >'yeah' : "yeah" @@ -408,7 +408,7 @@ let shortCutted: { a: number, b: string } = { ...o, a } >shortCutted : { a: number; b: string; } >a : number >b : string ->{ ...o, a } : { ...{ a: number; b: string; }; a: number; } +>{ ...o, a } : { a: number; b: string; } >o : any >a : number @@ -441,7 +441,7 @@ let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = >d : boolean f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { id: string; ...{ a: number; b: string; }; ...{ c: string; d: boolean; } } +>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { c: string; d: boolean; a: number; b: string; id: string; } >f : (t: T, u: U) => { id: string; ...T; ...U } >{ a: 1, b: 'yes' } : { a: number; b: string; } >a : number @@ -461,7 +461,7 @@ let overlap: { id: string, a: number, b: string } = >b : string f({ a: 1 }, { a: 2, b: 'extra' }) ->f({ a: 1 }, { a: 2, b: 'extra' }) : { id: string; ...{ a: number; }; ...{ a: number; b: string; } } +>f({ a: 1 }, { a: 2, b: 'extra' }) : { a: number; b: string; id: string; } >f : (t: T, u: U) => { id: string; ...T; ...U } >{ a: 1 } : { a: number; } >a : number @@ -478,7 +478,7 @@ let overlapConflict: { id:string, a: string } = >a : string f({ a: 1 }, { a: 'mismatch' }) ->f({ a: 1 }, { a: 'mismatch' }) : { id: string; ...{ a: number; }; ...{ a: string; } } +>f({ a: 1 }, { a: 'mismatch' }) : { a: string; id: string; } >f : (t: T, u: U) => { id: string; ...T; ...U } >{ a: 1 } : { a: number; } >a : number @@ -495,7 +495,7 @@ let overwriteId: { id: boolean, a: number, c: number, d: string } = >d : string f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f({ a: 1, id: true }, { c: 1, d: 'no' }) : { id: string; ...{ a: number; id: boolean; }; ...{ c: number; d: string; } } +>f({ a: 1, id: true }, { c: 1, d: 'no' }) : { c: number; d: string; a: number; id: boolean; } >f : (t: T, u: U) => { id: string; ...T; ...U } >{ a: 1, id: true } : { a: number; id: true; } >a : number @@ -515,13 +515,13 @@ class D { m() { }; q = 2; } >2 : 2 let classesAreWrong: { id: string, ...C, ...D } = ->classesAreWrong : { id: string; ...C; ...D } +>classesAreWrong : { q: number; p: number; id: string; } >id : string >C : C >D : D f(new C(), new D()) ->f(new C(), new D()) : { id: string; ...C; ...D } +>f(new C(), new D()) : { q: number; p: number; id: string; } >f : (t: T, u: U) => { id: string; ...T; ...U } >new C() : C >C : typeof C diff --git a/tests/baselines/reference/objectSpreadGeneric.errors.txt b/tests/baselines/reference/objectSpreadGeneric.errors.txt index 16dfc835d2607..6e55040f22391 100644 --- a/tests/baselines/reference/objectSpreadGeneric.errors.txt +++ b/tests/baselines/reference/objectSpreadGeneric.errors.txt @@ -1,22 +1,31 @@ -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(4,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(5,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...T; ...V }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(6,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(7,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(8,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(13,11): error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(26,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(34,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - Property 'first' is missing in type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(36,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - Property 'second' is missing in type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - Property 'third' is missing in type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(9,5): error TS2322: Type '{ ...U }' is not assignable to type 'U'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(10,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(11,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...T; ...V }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(12,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(13,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(14,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(19,11): error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(32,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(40,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + Property 'first' is missing in type '{ third: string; second: string; firrrrrrst: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(42,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + Property 'second' is missing in type '{ third: string; ssssssssecond: string; first: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + Property 'third' is missing in type '{ thirrrrrrrd: string; second: string; first: string; }'. -==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (10 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (11 errors) ==== function f(t: T, u: U, v: V): void { let o: { ...T, ...U, ...V }; + let uus: { ...U, ...U}; + let us: { ...U }; const same: { ...T, ...U, ...V } = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff + ~ +!!! error TS2322: Type '{ ...U }' is not assignable to type 'U'. const reversed: { ...V, ...U, ...T } = o; // error, reversed ~~~~~~~~ !!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. @@ -64,17 +73,17 @@ tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322 const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = ~~~~~~~~~~~~~ !!! error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -!!! error TS2322: Property 'first' is missing in type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }'. +!!! error TS2322: Property 'first' is missing in type '{ third: string; second: string; firrrrrrst: string; }'. { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = ~~~~~~~~~~~~~~ !!! error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -!!! error TS2322: Property 'second' is missing in type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }'. +!!! error TS2322: Property 'second' is missing in type '{ third: string; ssssssssecond: string; first: string; }'. { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = ~~~~~~~~~~~~ !!! error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -!!! error TS2322: Property 'third' is missing in type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }'. +!!! error TS2322: Property 'third' is missing in type '{ thirrrrrrrd: string; second: string; first: string; }'. { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found } \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadGeneric.js b/tests/baselines/reference/objectSpreadGeneric.js index 593ab73f98fac..9414b9ef76e86 100644 --- a/tests/baselines/reference/objectSpreadGeneric.js +++ b/tests/baselines/reference/objectSpreadGeneric.js @@ -1,7 +1,13 @@ //// [objectSpreadGeneric.ts] function f(t: T, u: U, v: V): void { let o: { ...T, ...U, ...V }; + let uus: { ...U, ...U}; + let us: { ...U }; const same: { ...T, ...U, ...V } = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff const reversed: { ...V, ...U, ...T } = o; // error, reversed const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed const missingT: { ...U, ...V } = o; // error, missing T @@ -52,7 +58,13 @@ var __assign = (this && this.__assign) || Object.assign || function(t) { }; function f(t, u, v) { var o; + var uus; + var us; var same = o; // ok + uus = us; // ok, multiple spreads are equivalent to a single one + us = uus; // ok, multiple spreads are equivalent to a single one + us = u; // ok, type has at least all the properties of the spread + u = us; // error, might be missing a ton of stuff var reversed = o; // error, reversed var reversed2 = o; // error, U and T are still reversed var missingT = o; // error, missing T diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types index 9a31b0c44512b..6e9ba881db1fb 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -9,7 +9,7 @@ class C { >c : boolean } let c: { ...C, b: string, c?: string, [n: number]: string }; ->c : { ...C; b: string; c?: string; [n: number]: string; } +>c : { [n: number]: string; b: string; c: string | boolean; a: number; } >C : C >b : string >c : string @@ -18,13 +18,13 @@ let c: { ...C, b: string, c?: string, [n: number]: string }; let n: number = c.a; >n : number >c.a : number ->c : { ...C; b: string; c?: string; [n: number]: string; } +>c : { [n: number]: string; b: string; c: string | boolean; a: number; } >a : number let s: string = c[12]; >s : string >c[12] : string ->c : { ...C; b: string; c?: string; [n: number]: string; } +>c : { [n: number]: string; b: string; c: string | boolean; a: number; } >12 : 12 interface Indexed { @@ -37,7 +37,7 @@ interface Indexed { >a : number } let i: { ...Indexed, b: number }; ->i : { ...Indexed; b: number; [n: string]: number; } +>i : { [n: string]: number; b: number; a: number; } >Indexed : Indexed >b : number @@ -45,14 +45,14 @@ n = i[101]; >n = i[101] : number >n : number >i[101] : number ->i : { ...Indexed; b: number; [n: string]: number; } +>i : { [n: string]: number; b: number; a: number; } >101 : 101 n = i.b; >n = i.b : number >n : number >i.b : number ->i : { ...Indexed; b: number; [n: string]: number; } +>i : { [n: string]: number; b: number; a: number; } >b : number interface Indexed2 { @@ -65,7 +65,7 @@ interface Indexed2 { >c : boolean } let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; ->ii : { ...Indexed; ...Indexed2; b: boolean; d: number; [x: string]: number | boolean; } +>ii : { [x: string]: number | boolean; b: boolean; d: number; c: boolean; a: number; } >Indexed : Indexed >Indexed2 : Indexed2 >b : boolean @@ -74,6 +74,6 @@ let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; let nb: number | boolean = ii[1001]; >nb : number | boolean >ii[1001] : number | boolean ->ii : { ...Indexed; ...Indexed2; b: boolean; d: number; [x: string]: number | boolean; } +>ii : { [x: string]: number | boolean; b: boolean; d: number; c: boolean; a: number; } >1001 : 1001 diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 1ee3acb823c6a..38e564c3b5d4f 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -1,20 +1,23 @@ -tests/cases/conformance/types/spread/objectSpreadNegative.ts(13,30): error TS2339: Property 'x' does not exist on type '{ ...PublicX; ...PrivateOptionalX }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(16,5): error TS2322: Type '{ ...{ sn?: string; }; ...{ sn?: number; } }' is not assignable to type '{ sn: string | number; }'. - Property 'sn' is optional in type '{ ...{ sn?: string; }; ...{ sn?: number; } }' but required in type '{ sn: string | number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(22,5): error TS2322: Type '{ s: string; }' is not assignable to type '{ ...Bool; ...Str }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(24,1): error TS2322: Type 'Bool' is not assignable to type '{ ...Bool; ...Str }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(27,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(31,36): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(31,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,12): error TS2339: Property 'b' does not exist on type '{ ...{ b: number; } }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,9): error TS2339: Property 'm' does not exist on type '{ ...C }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ ...PublicX }' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,39): error TS2697: Spread properties must be identifiers, property accesses, or object literals. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(11,21): error TS2339: Property 'x' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(14,5): error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'. + Property 'sn' is optional in type '{ sn?: string | number; }' but required in type '{ sn: string | number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(20,5): error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. + Property 'b' is missing in type '{ s: string; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(22,1): error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. + Property 's' is missing in type 'Bool'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(26,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(29,36): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(29,53): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,39): error TS2697: Spread properties must be identifiers, property accesses, or object literals. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (13 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (14 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -24,18 +27,16 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,39): error TS269 class PublicX { public x: number; } - let privateOptionalx: PrivateOptionalX; - let publicx: PublicX; - let o3 = { ...publicx, ...privateOptionalx }; - let sn: string | number = o3.x; // error, x is private - ~ -!!! error TS2339: Property 'x' does not exist on type '{ ...PublicX; ...PrivateOptionalX }'. + let o3: { ...PublicX, ...PrivateOptionalX }; + let sn: number = o3.x; // error, x is private + ~ +!!! error TS2339: Property 'x' does not exist on type '{}'. let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; ~~~~~~~~~~~ -!!! error TS2322: Type '{ ...{ sn?: string; }; ...{ sn?: number; } }' is not assignable to type '{ sn: string | number; }'. -!!! error TS2322: Property 'sn' is optional in type '{ ...{ sn?: string; }; ...{ sn?: number; } }' but required in type '{ sn: string | number; }'. +!!! error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'. +!!! error TS2322: Property 'sn' is optional in type '{ sn?: string | number; }' but required in type '{ sn: string | number; }'. // error, 'sn' is optional in source, required in target // assignability as target @@ -43,11 +44,13 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,39): error TS269 interface Str { s: string }; let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' ~~~~~~ -!!! error TS2322: Type '{ s: string; }' is not assignable to type '{ ...Bool; ...Str }'. +!!! error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. +!!! error TS2322: Property 'b' is missing in type '{ s: string; }'. let b: Bool; spread = b; // error, missing 's' ~~~~~~ -!!! error TS2322: Type 'Bool' is not assignable to type '{ ...Bool; ...Str }'. +!!! error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. +!!! error TS2322: Property 's' is missing in type 'Bool'. // expressions are not allowed let o1 = { ...1 + 1 }; @@ -69,7 +72,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,39): error TS269 let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist ~ -!!! error TS2339: Property 'b' does not exist on type '{ ...{ b: number; } }'. +!!! error TS2339: Property 'b' does not exist on type '{}'. // methods are skipped because they aren't enumerable class C { p = 1; m() { } } @@ -77,17 +80,25 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,39): error TS269 let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' ~ -!!! error TS2339: Property 'm' does not exist on type '{ ...C }'. +!!! error TS2339: Property 'm' does not exist on type '{ p: number; }'. let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; callableConstructableSpread(12); // error, no call signature ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ ...PublicX }' has no compatible call signatures. +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. new callableConstructableSpread(12); // error, no construct signature ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. + let publicx: PublicX; let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions ~~~~~~~~~~~~ !!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. + + // { ...U } is not assignable to U + function override(initial: U, override: U): U { + return { ...initial, ...override }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ ...U }' is not assignable to type 'U'. + } \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 685760f944467..6874380599b61 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -8,10 +8,8 @@ class PrivateOptionalX { class PublicX { public x: number; } -let privateOptionalx: PrivateOptionalX; -let publicx: PublicX; -let o3 = { ...publicx, ...privateOptionalx }; -let sn: string | number = o3.x; // error, x is private +let o3: { ...PublicX, ...PrivateOptionalX }; +let sn: number = o3.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; @@ -46,7 +44,13 @@ let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: numb callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature +let publicx: PublicX; let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions + +// { ...U } is not assignable to U +function override(initial: U, override: U): U { + return { ...initial, ...override }; +} //// [objectSpreadNegative.js] @@ -70,9 +74,7 @@ var PublicX = (function () { } return PublicX; }()); -var privateOptionalx; -var publicx; -var o3 = __assign({}, publicx, privateOptionalx); +var o3; var sn = o3.x; // error, x is private var optionalString; var optionalNumber; @@ -105,4 +107,9 @@ spreadC.m(); // error 'm' is not in '{ ... c }' var callableConstructableSpread; callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature +var publicx; var callableSpread = __assign({}, publicx, (function (n) { return n + 1; })); // error, can't spread functions +// { ...U } is not assignable to U +function override(initial, override) { + return __assign({}, initial, override); +} diff --git a/tests/baselines/reference/objectSpreadScenarios.js b/tests/baselines/reference/objectSpreadScenarios.js index 64739a2b298b0..96ac98d2d3593 100644 --- a/tests/baselines/reference/objectSpreadScenarios.js +++ b/tests/baselines/reference/objectSpreadScenarios.js @@ -4,7 +4,7 @@ interface B1 { b: number }; function override(initial: U, override: U): { ...U, ...U } { return { ...initial, ...override }; } -function update(this: { u: U }, override: U): void { +function update(this: { u: { ...U } }, override: U): void { this.u = { ...this.u, ...override }; } function mixin(one: T, two: U): { ...T, ...U } { diff --git a/tests/baselines/reference/objectSpreadScenarios.symbols b/tests/baselines/reference/objectSpreadScenarios.symbols index 784e340a10ce2..cf1e1833ac968 100644 --- a/tests/baselines/reference/objectSpreadScenarios.symbols +++ b/tests/baselines/reference/objectSpreadScenarios.symbols @@ -19,13 +19,13 @@ function override(initial: U, override: U): { ...U, ...U } { return { ...initial, ...override }; } -function update(this: { u: U }, override: U): void { +function update(this: { u: { ...U } }, override: U): void { >update : Symbol(update, Decl(objectSpreadScenarios.ts, 4, 1)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) >this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19)) >u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) ->override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 34)) +>override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 41)) >U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16)) this.u = { ...this.u, ...override }; diff --git a/tests/baselines/reference/objectSpreadScenarios.types b/tests/baselines/reference/objectSpreadScenarios.types index 5330029afe127..2d1aa47bd50a8 100644 --- a/tests/baselines/reference/objectSpreadScenarios.types +++ b/tests/baselines/reference/objectSpreadScenarios.types @@ -8,7 +8,7 @@ interface B1 { b: number }; >b : number function override(initial: U, override: U): { ...U, ...U } { ->override : (initial: U, override: U) => { ...U; ...U } +>override : (initial: U, override: U) => { ...U } >U : U >initial : U >U : U @@ -18,28 +18,28 @@ function override(initial: U, override: U): { ...U, ...U } { >U : U return { ...initial, ...override }; ->{ ...initial, ...override } : { ...U; ...U } +>{ ...initial, ...override } : { ...U } >initial : any >override : any } -function update(this: { u: U }, override: U): void { ->update : (this: { u: U; }, override: U) => void +function update(this: { u: { ...U } }, override: U): void { +>update : (this: { u: { ...U }; }, override: U) => void >U : U ->this : { u: U; } ->u : U +>this : { u: { ...U }; } +>u : { ...U } >U : U >override : U >U : U this.u = { ...this.u, ...override }; ->this.u = { ...this.u, ...override } : { ...U; ...U } ->this.u : U ->this : { u: U; } ->u : U ->{ ...this.u, ...override } : { ...U; ...U } ->this.u : U ->this : { u: U; } ->u : U +>this.u = { ...this.u, ...override } : { ...U } +>this.u : { ...U } +>this : { u: { ...U }; } +>u : { ...U } +>{ ...this.u, ...override } : { ...U } +>this.u : { ...U } +>this : { u: { ...U }; } +>u : { ...U } >override : any } function mixin(one: T, two: U): { ...T, ...U } { @@ -73,34 +73,34 @@ let b1: B1 = { b: 101 }; >101 : 101 a1 = override(a1, { a: false }); ->a1 = override(a1, { a: false }) : { ...A1; ...A1 } +>a1 = override(a1, { a: false }) : { a: boolean; } >a1 : A1 ->override(a1, { a: false }) : { ...A1; ...A1 } ->override : (initial: U, override: U) => { ...U; ...U } +>override(a1, { a: false }) : { a: boolean; } +>override : (initial: U, override: U) => { ...U } >a1 : A1 >{ a: false } : { a: false; } >a : boolean >false : false let host = { u: a1, update }; ->host : { u: A1; update: (this: { u: U; }, override: U) => void; } ->{ u: a1, update } : { u: A1; update: (this: { u: U; }, override: U) => void; } +>host : { u: A1; update: (this: { u: { ...U }; }, override: U) => void; } +>{ u: a1, update } : { u: A1; update: (this: { u: { ...U }; }, override: U) => void; } >u : A1 >a1 : A1 ->update : (this: { u: U; }, override: U) => void +>update : (this: { u: { ...U }; }, override: U) => void host.update({ a: false }); >host.update({ a: false }) : void ->host.update : (this: { u: U; }, override: U) => void ->host : { u: A1; update: (this: { u: U; }, override: U) => void; } ->update : (this: { u: U; }, override: U) => void +>host.update : (this: { u: { ...U }; }, override: U) => void +>host : { u: A1; update: (this: { u: { ...U }; }, override: U) => void; } +>update : (this: { u: { ...U }; }, override: U) => void >{ a: false } : { a: false; } >a : boolean >false : false let mixed = mixin(a1, b1); ->mixed : { ...A1; ...B1 } ->mixin(a1, b1) : { ...A1; ...B1 } +>mixed : { b: number; a: boolean; } +>mixin(a1, b1) : { b: number; a: boolean; } >mixin : (one: T, two: U) => { ...T; ...U } >a1 : A1 >b1 : B1 diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index 9dd9a8d41a1bf..46782aaa1d69d 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -1,4 +1,4 @@ -lib.d.ts(28,18): error TS2300: Duplicate identifier 'eval'. +lib.d.ts(32,18): error TS2300: Duplicate identifier 'eval'. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS1100: Invalid use of 'eval' in strict mode. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Duplicate identifier 'eval'. From 4eedfea81f4603d307829268ea934b7ccf725a3e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 10 Oct 2016 10:05:31 -0700 Subject: [PATCH 22/85] Support unions/intersections in spread types 1. Lift unions and intersections above spread types when creating them in getSpreadType. 2. Cleanup now-unneeded changes to existing union/intersection code. 3. Cleanup some incorrect errors I added earlier. --- src/compiler/checker.ts | 263 +++++++++++++-------------- src/compiler/diagnosticMessages.json | 10 +- src/compiler/types.ts | 12 +- src/services/findAllReferences.ts | 6 +- 4 files changed, 134 insertions(+), 157 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0e7266b223ccd..9d8ea29a3819b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2197,7 +2197,7 @@ namespace ts { writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); } else if (type.flags & TypeFlags.UnionOrIntersection) { - writeUnionOrIntersectionType(type, nextFlags); + writeUnionOrIntersectionType(type, nextFlags); } else if (type.flags & TypeFlags.Spread) { writeSpreadType(type, nextFlags); @@ -2291,7 +2291,7 @@ namespace ts { } } - function writeUnionOrIntersectionType(type: TypeOperatorType, flags: TypeFormatFlags) { + function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) { if (flags & TypeFormatFlags.InElementType) { writePunctuation(writer, SyntaxKind.OpenParenToken); } @@ -4449,7 +4449,7 @@ namespace ts { } } - function getPropertiesOfUnionOrIntersectionType(type: TypeOperatorType): Symbol[] { + function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] { for (const current of type.types) { for (const prop of getPropertiesOfType(current)) { getUnionOrIntersectionProperty(type, prop.name); @@ -4499,7 +4499,7 @@ namespace ts { } function getApparentTypeOfSpread(type: SpreadType) { - return getSpreadType([getApparentType(type.left), getApparentType(type.right)], type.symbol, undefined, undefined); + return getSpreadType([getApparentType(type.left), getApparentType(type.right)], type.symbol); } /** @@ -4529,44 +4529,35 @@ namespace ts { return type; } - function createUnionOrIntersectionProperty(containingType: TypeOperatorType, name: string): Symbol { + function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string) { const types = containingType.types; - return createUnionOrIntersectionOrSpreadPropertySymbol(containingType, name, () => { - let props: Symbol[]; - // Flags we want to propagate to the result if they exist in all source symbols - let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None; - let isReadonly = false; - let isPartial = false; - for (const current of types) { - const type = getApparentType(current); - if (type !== unknownType) { - const prop = getPropertyOfType(type, name); - if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) { - commonFlags &= prop.flags; - if (!props) { - props = [prop]; - } - else if (!contains(props, prop)) { - props.push(prop); - } - if (isReadonlySymbol(prop)) { - isReadonly = true; - } - + let props: Symbol[]; + // Flags we want to propagate to the result if they exist in all source symbols + let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None; + let isReadonly = false; + let isPartial = false; + for (const current of types) { + const type = getApparentType(current); + if (type !== unknownType) { + const prop = getPropertyOfType(type, name); + if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) { + commonFlags &= prop.flags; + if (!props) { + props = [prop]; + } + else if (!contains(props, prop)) { + props.push(prop); } - else if (containingType.flags & TypeFlags.Union) { - isPartial = true; + if (isReadonlySymbol(prop)) { + isReadonly = true; } + + } + else if (containingType.flags & TypeFlags.Union) { + isPartial = true; } } - return [props, isReadonly, isPartial, commonFlags]; - }); - } - - function createUnionOrIntersectionOrSpreadPropertySymbol(containingType: TypeOperatorType, - name: string, - symbolCreator: () => [Symbol[], boolean, boolean, SymbolFlags]) { - const [props, isReadonly, isPartial, flags] = symbolCreator(); + } if (!props) { return undefined; } @@ -4590,7 +4581,7 @@ namespace ts { } propTypes.push(type); } - const result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | flags, name); + const result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | commonFlags, name); result.syntheticKind === SyntheticSymbolKind.UnionOrIntersection; result.containingType = containingType; result.hasNonUniformType = hasNonUniformType; @@ -4609,7 +4600,7 @@ namespace ts { // constituents, in which case the isPartial flag is set when the containing type is union type. We need // these partial properties when identifying discriminant properties, but otherwise they are filtered out // and do not appear to be present in the union type. - function getUnionOrIntersectionProperty(type: TypeOperatorType, name: string): Symbol { + function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: string): Symbol { const properties = type.resolvedProperties || (type.resolvedProperties = createMap()); let property = properties[name]; if (!property) { @@ -4621,7 +4612,7 @@ namespace ts { return property; } - function getPropertyOfUnionOrIntersectionType(type: TypeOperatorType, name: string): Symbol { + function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol { const property = getUnionOrIntersectionProperty(type, name); // We need to filter out partial properties in union types return property && !(property.flags & SymbolFlags.SyntheticProperty && (property).isPartial) ? property : undefined; @@ -4652,7 +4643,7 @@ namespace ts { return getPropertyOfObjectType(globalObjectType, name); } if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertyOfUnionOrIntersectionType(type, name); + return getPropertyOfUnionOrIntersectionType(type, name); } return undefined; } @@ -5773,6 +5764,9 @@ namespace ts { return spreadTypes[id]; } const right = types.pop(); + if (right.flags & TypeFlags.Any) { + return anyType; + } if (right.flags & TypeFlags.Spread) { // spread is right associative and associativity applies, so transform // (T ... U) ... V to T ... (U ... V) @@ -5783,9 +5777,22 @@ namespace ts { types.push(rspread.right); return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); } + if (right.flags & TypeFlags.Intersection) { + const spreads = map((right as IntersectionType).types, + t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); + return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments); + } + if (right.flags & TypeFlags.Union) { + // TODO: types is mutable, so this block has to happen before the call to `const left = getSpreadType(...)` + // because that call consumes the array. It might be worthwhile to use a simple linked list here instead. + // It would avoid the slice+concat call that is needed here for multiple calls to getSpreadType. + const spreads = map((right as UnionType).types, + t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); + return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); + } const atBeginning = types.length === 0; const left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); - if (right.flags & (TypeFlags.Null | TypeFlags.Undefined)) { + if (right.flags & TypeFlags.Primitive || left.flags & TypeFlags.Any) { return left; } if (right.flags & TypeFlags.TypeParameter && @@ -5795,9 +5802,18 @@ namespace ts { // for types like T ... T, just return ... T return left; } - if (!(right.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.TypeParameter | TypeFlags.Spread)) - && !(left.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.TypeParameter | TypeFlags.Spread))) { - const members = createMap(); + if (left.flags & TypeFlags.Intersection) { + const spreads = map((left as IntersectionType).types, + t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); + return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments); + } + if (left.flags & TypeFlags.Union) { + const spreads = map((left as UnionType).types, + t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); + return getUnionType(spreads, /*subTypeReduction*/ false, aliasSymbol, aliasTypeArguments); + } + if (right.flags & TypeFlags.ObjectType && left.flags & TypeFlags.ObjectType) { + const members = createMap(); const skippedPrivateMembers = createMap(); let stringIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); let numberIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); @@ -5820,7 +5836,6 @@ namespace ts { for (const leftProp of getPropertiesOfType(left)) { if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor) || leftProp.name in skippedPrivateMembers) { - // skip set-only properties (methods have already been skipped by the recursive call to getSpreadType) continue; } if (leftProp.name in members) { @@ -5836,7 +5851,7 @@ namespace ts { if (declarations.length) { result.valueDeclaration = declarations[0]; } - result.isReadonly = isReadonlySymbol(rightProp) || isReadonlySymbol(leftProp); + result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp); members[leftProp.name] = result; } } @@ -5846,10 +5861,9 @@ namespace ts { } return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } - // one side is a type parameter (TODO: Or union or intersection) const spread = spreadTypes[id] = createObjectType(TypeFlags.Spread, symbol) as SpreadType; - Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.ObjectType))); - Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.ObjectType))); + Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.ObjectType)), "Left flags: " + left.flags.toString(2)); + Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.ObjectType)), "Right flags: " + right.flags.toString(2)); spread.left = left as SpreadType | ResolvedType; spread.right = right as TypeParameter | ResolvedType; spread.aliasSymbol = aliasSymbol; @@ -6802,19 +6816,19 @@ namespace ts { } } - if (source.flags & TypeFlags.Spread) { - // you only see this for spreads with type parameters (TODO: and unions/intersections) - if (target.flags & TypeFlags.Spread) { - if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType))) { + if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { + // you only see this for spreads with type parameters + if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType))) { + if (reportErrors) { reportRelationError(headMessage, source, target); - return Ternary.False; - } - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; - const apparentSource = getApparentType(source); - if (result = objectTypeRelatedTo(apparentSource, source, getApparentType(target), reportStructuralErrors)) { - errorInfo = saveErrorInfo; - return result; } + return Ternary.False; + } + const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; + const apparentSource = getApparentType(source); + if (result = objectTypeRelatedTo(apparentSource, source, getApparentType(target), reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; } } @@ -6878,40 +6892,27 @@ namespace ts { } function spreadTypeRelatedTo(source: SpreadType, target: SpreadType): boolean { - // (Spread ... Object) | (Spread | Object ... TypeParameter) - // in other words, if the right side is Object, then the left side must be a Spread. - if (source.right.flags & TypeFlags.ObjectType && - target.right.flags & TypeFlags.ObjectType) { - return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); - } - if (source.right.flags & TypeFlags.ObjectType) { - /// target.right is TypeParameter, skip source.right, but keep looking at target - return spreadTypeRelatedTo(source.left as SpreadType, target); - } - if (target.right.flags & TypeFlags.ObjectType) { - /// source.right is TypeParameter, skip target.right, but keep looking at source - return spreadTypeRelatedTo(source, target.left as SpreadType); + // If the right side of a spread type is ObjectType, then the left side must be a Spread. + // Structural compatibility of the spreads' object types are checked separately in isRelatedTo, + // so just skip them for now. + if (source.right.flags & TypeFlags.ObjectType || target.right.flags & TypeFlags.ObjectType) { + return spreadTypeRelatedTo(source.right.flags & TypeFlags.ObjectType ? source.left as SpreadType : source, + target.right.flags & TypeFlags.ObjectType ? target.left as SpreadType : target); + } + // If both right sides are type parameters, then they must be identical for the spread types to be related. + // It also means that the left sides are either spread types or object types. + + // if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed + if (target.right.symbol !== source.right.symbol) { + return false; } - else { - // both rights are type parameters, so they must be identical - // and both lefts must be the same: - // if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed - if (target.right.symbol !== source.right.symbol) { - return false; - } - if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) { - return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); - } - else if (source.left.flags & TypeFlags.ObjectType && target.left.flags & TypeFlags.ObjectType) { - return true; // let structural compatibility figure it out later - } - else { - // one side is a spread, so it must have more type parameters, which will not be matched by the other side - // return false immediately instead of descending to find this out. - return false; - } + if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) { + // If the left sides are both spread types, then recursively check them. + return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); } - + // If the left sides are both object types, then isRelatedTo will check the structural compatibility next. + // Otherwise, one side has more type parameters than the other and the spread types are not related. + return !!(source.left.flags & TypeFlags.ObjectType && target.left.flags & TypeFlags.ObjectType); } function isIdenticalTo(source: Type, target: Type): Ternary { @@ -6927,8 +6928,8 @@ namespace ts { } if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union || source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) { - if (result = eachTypeRelatedToSomeType(source, target, /*reportErrors*/ false)) { - if (result &= eachTypeRelatedToSomeType(target, source, /*reportErrors*/ false)) { + if (result = eachTypeRelatedToSomeType(source, target, /*reportErrors*/ false)) { + if (result &= eachTypeRelatedToSomeType(target, source, /*reportErrors*/ false)) { return result; } } @@ -6951,7 +6952,7 @@ namespace ts { } } else if (type.flags & TypeFlags.UnionOrIntersection) { - for (const t of (type).types) { + for (const t of (type).types) { if (isKnownProperty(t, name)) { return true; } @@ -6989,7 +6990,7 @@ namespace ts { return false; } - function eachTypeRelatedToSomeType(source: TypeOperatorType, target: TypeOperatorType, reportErrors: boolean): Ternary { + function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { @@ -7002,7 +7003,7 @@ namespace ts { return result; } - function typeRelatedToSomeType(source: Type, target: TypeOperatorType, reportErrors: boolean): Ternary { + function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { const targetTypes = target.types; if (target.flags & TypeFlags.Union && containsType(targetTypes, source)) { return Ternary.True; @@ -7017,7 +7018,7 @@ namespace ts { return Ternary.False; } - function typeRelatedToEachType(source: Type, target: TypeOperatorType, reportErrors: boolean): Ternary { + function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { @@ -7030,7 +7031,7 @@ namespace ts { return result; } - function someTypeRelatedToType(source: TypeOperatorType, target: Type, reportErrors: boolean): Ternary { + function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { const sourceTypes = source.types; if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { return Ternary.True; @@ -7045,7 +7046,7 @@ namespace ts { return Ternary.False; } - function eachTypeRelatedToType(source: TypeOperatorType, target: Type, reportErrors: boolean): Ternary { + function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { @@ -7990,10 +7991,10 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter || type.flags & TypeFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || - type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); + type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); } - function couldUnionOrIntersectionContainTypeParameters(type: TypeOperatorType): boolean { + function couldUnionOrIntersectionContainTypeParameters(type: UnionOrIntersectionType): boolean { if (type.couldContainTypeParameters === undefined) { type.couldContainTypeParameters = forEach(type.types, couldContainTypeParameters); } @@ -8001,7 +8002,7 @@ namespace ts { } function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { - return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((type).types, t => isTypeParameterAtTopLevel(t, typeParameter)); + return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((type).types, t => isTypeParameterAtTopLevel(t, typeParameter)); } function inferTypes(context: InferenceContext, originalSource: Type, originalTarget: Type) { @@ -8031,7 +8032,7 @@ namespace ts { // Source and target are both unions or both intersections. If source and target // are the same type, just relate each constituent type to itself. if (source === target) { - for (const t of (source).types) { + for (const t of (source).types) { inferFromTypes(t, t); } return; @@ -8043,14 +8044,14 @@ namespace ts { // and string literals because the number and string types are not represented as unions // of all their possible values. let matchingTypes: Type[]; - for (const t of (source).types) { - if (typeIdenticalToSomeType(t, (target).types)) { + for (const t of (source).types) { + if (typeIdenticalToSomeType(t, (target).types)) { (matchingTypes || (matchingTypes = [])).push(t); inferFromTypes(t, t); } else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) { const b = getBaseTypeOfLiteralType(t); - if (typeIdenticalToSomeType(b, (target).types)) { + if (typeIdenticalToSomeType(b, (target).types)) { (matchingTypes || (matchingTypes = [])).push(t, b); } } @@ -8059,8 +8060,8 @@ namespace ts { // removing the identically matched constituents. For example, when inferring from // 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'. if (matchingTypes) { - source = removeTypesFromUnionOrIntersection(source, matchingTypes); - target = removeTypesFromUnionOrIntersection(target, matchingTypes); + source = removeTypesFromUnionOrIntersection(source, matchingTypes); + target = removeTypesFromUnionOrIntersection(target, matchingTypes); } } if (target.flags & TypeFlags.TypeParameter) { @@ -8107,7 +8108,7 @@ namespace ts { } } else if (target.flags & TypeFlags.UnionOrIntersection) { - const targetTypes = (target).types; + const targetTypes = (target).types; let typeParameterCount = 0; let typeParameter: TypeParameter; // First infer to each type in union or intersection that isn't a type parameter @@ -8131,7 +8132,7 @@ namespace ts { } else if (source.flags & TypeFlags.UnionOrIntersection) { // Source is a union or intersection type, infer from each constituent type - const sourceTypes = (source).types; + const sourceTypes = (source).types; for (const sourceType of sourceTypes) { inferFromTypes(sourceType, target); } @@ -8236,7 +8237,7 @@ namespace ts { * Return a new union or intersection type computed by removing a given set of types * from a given union or intersection type. */ - function removeTypesFromUnionOrIntersection(type: TypeOperatorType, typesToRemove: Type[]) { + function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) { const reducedTypes: Type[] = []; for (const t of type.types) { if (!typeIdenticalToSomeType(t, typesToRemove)) { @@ -8549,7 +8550,7 @@ namespace ts { return getTypeFacts(constraint || emptyObjectType); } if (flags & TypeFlags.UnionOrIntersection) { - return getTypeFactsOfTypes((type).types); + return getTypeFactsOfTypes((type).types); } return TypeFacts.All; } @@ -10632,13 +10633,6 @@ namespace ts { type = checkExpressionForMutableLocation((memberDecl).name, contextualMapper); } - if (hasProperty(propertiesTable, member.name)) { - const existingPropType = getTypeOfSymbol(propertiesTable[member.name]); - if (!isTypeIdenticalTo(existingPropType, type)) { - error(memberDecl.name, Diagnostics.Cannot_change_type_of_property_0_from_1_to_2, member.name, typeToString(existingPropType), typeToString(type)); - } - } - typeFlags |= type.flags; const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name); if (inDestructuringPattern) { @@ -10992,7 +10986,7 @@ namespace ts { elemType = checkExpression(node.tagName); } if (elemType.flags & TypeFlags.Union) { - const types = (elemType).types; + const types = (elemType).types; return getUnionType(types.map(type => { return getResolvedJsxType(node, type, elemClassType); }), /*subtypeReduction*/ true); @@ -13557,7 +13551,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { - const types = (type).types; + const types = (type).types; for (const t of types) { if (maybeTypeOfKind(t, kind)) { return true; @@ -13575,7 +13569,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.Union) { - const types = (type).types; + const types = (type).types; for (const t of types) { if (!isTypeOfKind(t, kind)) { return false; @@ -13584,7 +13578,7 @@ namespace ts { return true; } if (type.flags & TypeFlags.Intersection) { - const types = (type).types; + const types = (type).types; for (const t of types) { if (isTypeOfKind(t, kind)) { return true; @@ -14980,9 +14974,11 @@ namespace ts { forEach(node.members, checkSourceElement); if (produceDiagnostics) { const type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); - checkIndexConstraints(type); - checkTypeForDuplicateIndexSignatures(node); - checkObjectTypeForDuplicateDeclarations(node); + if (type.flags & TypeFlags.ObjectType) { + checkIndexConstraints(type); + checkTypeForDuplicateIndexSignatures(node); + checkObjectTypeForDuplicateDeclarations(node); + } } } @@ -20317,17 +20313,6 @@ namespace ts { for (const prop of node.properties) { if (prop.kind === SyntaxKind.SpreadElementExpression) { - const target = (prop as SpreadElementExpression).expression; - switch (target.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.NullKeyword: - break; - default: - grammarErrorOnNode(target, Diagnostics.Spread_properties_must_be_identifiers_property_accesses_or_object_literals); - } - continue; } const name = prop.name; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 37a335f67cf54..65d67b6bf8392 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1967,17 +1967,9 @@ "category": "Error", "code": 2696 }, - "Spread properties must be identifiers, property accesses, or object literals.": { - "category": "Error", - "code": 2697 - }, - "Cannot change type of property '{0}' from '{1}' to '{2}'.": { - "category": "Error", - "code": 2698 - }, "Interface declaration cannot contain a spread property.": { "category": "Error", - "code": 2699 + "code": 2697 }, "Import declaration '{0}' is using private name '{1}'.": { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 75aaf03f08b19..0914f0ba41403 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1802,7 +1802,7 @@ namespace ts { export interface JSDocRecordType extends JSDocType { kind: SyntaxKind.JSDocRecordType; - literal: TypeLiteralNode; + literal: TypeLiteralNode; } export interface JSDocTypeReference extends JSDocType { @@ -2536,7 +2536,7 @@ namespace ts { instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) mapper?: TypeMapper; // Type mapper for instantiation alias referenced?: boolean; // True if alias symbol has been referenced as a value - containingType?: TypeOperatorType; // Containing union or intersection type for synthetic property + containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property leftSpread?: Symbol; // Left source for synthetic spread property rightSpread?: Symbol; // Right source for synthetic spread property hasNonUniformType?: boolean; // True if constituents have non-uniform types @@ -2755,7 +2755,7 @@ namespace ts { instantiations: Map; // Generic instantiation cache } - export interface TypeOperatorType extends Type { + export interface UnionOrIntersectionType extends Type { types: Type[]; // Constituent types /* @internal */ resolvedProperties: SymbolTable; // Cache of resolved properties @@ -2763,9 +2763,9 @@ namespace ts { couldContainTypeParameters: boolean; } - export interface UnionType extends TypeOperatorType { } + export interface UnionType extends UnionOrIntersectionType { } - export interface IntersectionType extends TypeOperatorType { } + export interface IntersectionType extends UnionOrIntersectionType { } /* @internal */ export interface SpreadType extends Type { @@ -2782,7 +2782,7 @@ namespace ts { /* @internal */ // Resolved object, spread, union, or intersection type - export interface ResolvedType extends ObjectType, TypeOperatorType { + export interface ResolvedType extends ObjectType, UnionOrIntersectionType { members: SymbolTable; // Properties by name properties: Symbol[]; // Properties callSignatures: Signature[]; // Call signatures of type diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 8766937c00851..dcda3e40b1a67 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -458,7 +458,7 @@ namespace ts.FindAllReferences { return [localParentType.symbol]; } else if (localParentType.flags & TypeFlags.UnionOrIntersection) { - return getSymbolsForClassAndInterfaceComponents(localParentType); + return getSymbolsForClassAndInterfaceComponents(localParentType); } } } @@ -630,13 +630,13 @@ namespace ts.FindAllReferences { } } - function getSymbolsForClassAndInterfaceComponents(type: TypeOperatorType, result: Symbol[] = []): Symbol[] { + function getSymbolsForClassAndInterfaceComponents(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] { for (const componentType of type.types) { if (componentType.symbol && componentType.symbol.getFlags() & (SymbolFlags.Class | SymbolFlags.Interface)) { result.push(componentType.symbol); } if (componentType.getFlags() & TypeFlags.UnionOrIntersection) { - getSymbolsForClassAndInterfaceComponents(componentType, result); + getSymbolsForClassAndInterfaceComponents(componentType, result); } } return result; From 0dd1f0c00f641b98de531c165d884cfe2728927a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 10 Oct 2016 10:07:41 -0700 Subject: [PATCH 23/85] Add tests and update baselines. 1. Union/intersection tests. 2. Primitive tests. 3. Update baselines after removing errors. --- .../duplicateObjectLiteralProperty.errors.txt | 8 +- .../reference/interfaceSpread.errors.txt | 4 +- .../lastPropertyInLiteralWins.errors.txt | 8 +- .../reference/memberOverride.errors.txt | 5 +- .../reference/objectLiteralErrors.errors.txt | 5 +- ...tiesErrorFromNotUsingIdentifier.errors.txt | 8 +- tests/baselines/reference/objectSpread.js | 22 +- .../baselines/reference/objectSpread.symbols | 258 +++++++++--------- tests/baselines/reference/objectSpread.types | 43 +-- .../reference/objectSpreadIntersection.js | 79 ++++++ .../objectSpreadIntersection.symbols | 219 +++++++++++++++ .../reference/objectSpreadIntersection.types | 236 ++++++++++++++++ .../reference/objectSpreadNegative.errors.txt | 76 ++++-- .../reference/objectSpreadNegative.js | 56 ++-- .../baselines/reference/objectSpreadUnion.js | 52 ++++ .../reference/objectSpreadUnion.symbols | 122 +++++++++ .../reference/objectSpreadUnion.types | 131 +++++++++ .../conformance/types/spread/objectSpread.ts | 12 +- .../types/spread/objectSpreadIntersection.ts | 36 +++ .../types/spread/objectSpreadNegative.ts | 30 +- .../types/spread/objectSpreadUnion.ts | 23 ++ 21 files changed, 1194 insertions(+), 239 deletions(-) create mode 100644 tests/baselines/reference/objectSpreadIntersection.js create mode 100644 tests/baselines/reference/objectSpreadIntersection.symbols create mode 100644 tests/baselines/reference/objectSpreadIntersection.types create mode 100644 tests/baselines/reference/objectSpreadUnion.js create mode 100644 tests/baselines/reference/objectSpreadUnion.symbols create mode 100644 tests/baselines/reference/objectSpreadUnion.types create mode 100644 tests/cases/conformance/types/spread/objectSpreadIntersection.ts create mode 100644 tests/cases/conformance/types/spread/objectSpreadUnion.ts diff --git a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt index 926a707122293..abc56a6f8fce7 100644 --- a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt +++ b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt @@ -1,8 +1,6 @@ tests/cases/compiler/duplicateObjectLiteralProperty.ts(4,5): error TS2300: Duplicate identifier 'a'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(5,5): error TS2300: Duplicate identifier '\u0061'. -tests/cases/compiler/duplicateObjectLiteralProperty.ts(5,5): error TS2698: Cannot change type of property 'a' from 'number' to 'string'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(6,5): error TS2300: Duplicate identifier 'a'. -tests/cases/compiler/duplicateObjectLiteralProperty.ts(6,5): error TS2698: Cannot change type of property 'a' from 'string' to '{ c: number; }'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(8,9): error TS2300: Duplicate identifier '"c"'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(14,9): error TS2300: Duplicate identifier 'a'. tests/cases/compiler/duplicateObjectLiteralProperty.ts(15,9): error TS2300: Duplicate identifier 'a'. @@ -10,7 +8,7 @@ tests/cases/compiler/duplicateObjectLiteralProperty.ts(16,9): error TS1118: An o tests/cases/compiler/duplicateObjectLiteralProperty.ts(16,9): error TS2300: Duplicate identifier 'a'. -==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (10 errors) ==== +==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (8 errors) ==== var x = { a: 1, b: true, // OK @@ -20,13 +18,9 @@ tests/cases/compiler/duplicateObjectLiteralProperty.ts(16,9): error TS2300: Dupl \u0061: "ss", // Duplicate ~~~~~~ !!! error TS2300: Duplicate identifier '\u0061'. - ~~~~~~ -!!! error TS2698: Cannot change type of property 'a' from 'number' to 'string'. a: { ~ !!! error TS2300: Duplicate identifier 'a'. - ~ -!!! error TS2698: Cannot change type of property 'a' from 'string' to '{ c: number; }'. c: 1, "c": 56, // Duplicate ~~~ diff --git a/tests/baselines/reference/interfaceSpread.errors.txt b/tests/baselines/reference/interfaceSpread.errors.txt index 2b27c972cc895..d8556de9f9379 100644 --- a/tests/baselines/reference/interfaceSpread.errors.txt +++ b/tests/baselines/reference/interfaceSpread.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/types/spread/interfaceSpread.ts(2,5): error TS2699: Interface declaration cannot contain a spread property. +tests/cases/conformance/types/spread/interfaceSpread.ts(2,5): error TS2697: Interface declaration cannot contain a spread property. tests/cases/conformance/types/spread/interfaceSpread.ts(7,10): error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. tests/cases/conformance/types/spread/interfaceSpread.ts(8,10): error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'. @@ -7,7 +7,7 @@ tests/cases/conformance/types/spread/interfaceSpread.ts(8,10): error TS2339: Pro interface Congealed { ...T ~~~~ -!!! error TS2699: Interface declaration cannot contain a spread property. +!!! error TS2697: Interface declaration cannot contain a spread property. ...U } diff --git a/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt b/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt index c8844f2c5721f..2b4a694975b4c 100644 --- a/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt +++ b/tests/baselines/reference/lastPropertyInLiteralWins.errors.txt @@ -4,12 +4,10 @@ tests/cases/compiler/lastPropertyInLiteralWins.ts(7,6): error TS2345: Argument o Types of parameters 'num' and 'str' are incompatible. Type 'string' is not assignable to type 'number'. tests/cases/compiler/lastPropertyInLiteralWins.ts(9,5): error TS2300: Duplicate identifier 'thunk'. -tests/cases/compiler/lastPropertyInLiteralWins.ts(9,5): error TS2698: Cannot change type of property 'thunk' from '(str: string) => void' to '(num: number) => void'. tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2300: Duplicate identifier 'thunk'. -tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2698: Cannot change type of property 'thunk' from '(num: number) => void' to '(str: string) => void'. -==== tests/cases/compiler/lastPropertyInLiteralWins.ts (5 errors) ==== +==== tests/cases/compiler/lastPropertyInLiteralWins.ts (3 errors) ==== interface Thing { thunk: (str: string) => void; } @@ -24,8 +22,6 @@ tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2698: Cannot ch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~ !!! error TS2300: Duplicate identifier 'thunk'. - ~~~~~ -!!! error TS2698: Cannot change type of property 'thunk' from '(str: string) => void' to '(num: number) => void'. }); ~ !!! error TS2345: Argument of type '{ thunk: (num: number) => void; }' is not assignable to parameter of type 'Thing'. @@ -39,7 +35,5 @@ tests/cases/compiler/lastPropertyInLiteralWins.ts(14,5): error TS2698: Cannot ch thunk: (str: string) => {} ~~~~~ !!! error TS2300: Duplicate identifier 'thunk'. - ~~~~~ -!!! error TS2698: Cannot change type of property 'thunk' from '(num: number) => void' to '(str: string) => void'. }); \ No newline at end of file diff --git a/tests/baselines/reference/memberOverride.errors.txt b/tests/baselines/reference/memberOverride.errors.txt index 355db0015057f..15c4b2ad37bb8 100644 --- a/tests/baselines/reference/memberOverride.errors.txt +++ b/tests/baselines/reference/memberOverride.errors.txt @@ -1,8 +1,7 @@ tests/cases/compiler/memberOverride.ts(5,5): error TS2300: Duplicate identifier 'a'. -tests/cases/compiler/memberOverride.ts(5,5): error TS2698: Cannot change type of property 'a' from 'string' to 'number'. -==== tests/cases/compiler/memberOverride.ts (2 errors) ==== +==== tests/cases/compiler/memberOverride.ts (1 errors) ==== // An object initialiser accepts the first definition for the same property with a different type signature // Should compile, since the second declaration of a overrides the first var x = { @@ -10,8 +9,6 @@ tests/cases/compiler/memberOverride.ts(5,5): error TS2698: Cannot change type of a: 5 ~ !!! error TS2300: Duplicate identifier 'a'. - ~ -!!! error TS2698: Cannot change type of property 'a' from 'string' to 'number'. } var n: number = x.a; \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralErrors.errors.txt b/tests/baselines/reference/objectLiteralErrors.errors.txt index f70f255df05b8..234ac24a8fdc5 100644 --- a/tests/baselines/reference/objectLiteralErrors.errors.txt +++ b/tests/baselines/reference/objectLiteralErrors.errors.txt @@ -1,7 +1,6 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(3,18): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(4,19): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(5,18): error TS2300: Duplicate identifier 'a'. -tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(5,18): error TS2698: Cannot change type of property 'a' from 'number' to 'string'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(6,21): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(7,19): error TS2300: Duplicate identifier 'a'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(8,18): error TS2300: Duplicate identifier ''a''. @@ -79,7 +78,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,16) tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,55): error TS2380: 'get' and 'set' accessor must have the same type. -==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (79 errors) ==== +==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (78 errors) ==== // Multiple properties with the same name var e1 = { a: 0, a: 0 }; @@ -91,8 +90,6 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,55) var e3 = { a: 0, a: '' }; ~ !!! error TS2300: Duplicate identifier 'a'. - ~ -!!! error TS2698: Cannot change type of property 'a' from 'number' to 'string'. var e4 = { a: true, a: false }; ~ !!! error TS2300: Duplicate identifier 'a'. diff --git a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt index cbe19cab2d25b..5fa8a12e87559 100644 --- a/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt +++ b/tests/baselines/reference/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.errors.txt @@ -8,14 +8,12 @@ tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPr tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(10,10): error TS1005: ':' expected. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(12,1): error TS1005: ':' expected. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(15,6): error TS1005: ':' expected. -tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(16,5): error TS2698: Cannot change type of property 'a' from 'any' to 'string[]'. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(16,6): error TS1005: ':' expected. -tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(17,5): error TS2698: Cannot change type of property 'a' from 'string[]' to 'number[]'. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(17,6): error TS1005: ':' expected. tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(20,17): error TS1005: ':' expected. -==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts (15 errors) ==== +==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts (13 errors) ==== // errors var y = { "stringLiteral", @@ -52,13 +50,9 @@ tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPr ~ !!! error TS1005: ':' expected. a["ss"], - ~ -!!! error TS2698: Cannot change type of property 'a' from 'any' to 'string[]'. ~ !!! error TS1005: ':' expected. a[1], - ~ -!!! error TS2698: Cannot change type of property 'a' from 'string[]' to 'number[]'. ~ !!! error TS1005: ':' expected. }; diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index a59577fe9dece..a09f5aa0fbb1a 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -35,11 +35,13 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null and undefined are just skipped -let spreadNull: { a: number } = - { a: 7, ...null } -let spreadUndefined: { a: number } = - { a: 7, ...undefined } +// null, undefined, functions and primitives result in { } +let spreadNull = { ...null }; +let spreadUndefind = { ...undefined }; +let spreadNum = { ...12 }; +let spreadStr = { ...'foo' }; +let spreadBool = { ...false }; +let spreadFunc = { ...(function () { }) }; // methods are not enumerable class C { p = 1; m() { } } @@ -126,9 +128,13 @@ var propertyNested = __assign({ a: __assign({}, o) }); var op = { get a() { return 6; } }; var getter = __assign({}, op, { c: 7 }); getter.a = 12; -// null and undefined are just skipped -var spreadNull = __assign({ a: 7 }, null); -var spreadUndefined = __assign({ a: 7 }, undefined); +// null, undefined, functions and primitives result in { } +var spreadNull = __assign({}, null); +var spreadUndefind = __assign({}, undefined); +var spreadNum = __assign({}, 12); +var spreadStr = __assign({}, 'foo'); +var spreadBool = __assign({}, false); +var spreadFunc = __assign({}, (function () { })); // methods are not enumerable var C = (function () { function C() { diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 001c42804d2b4..edb0b4c2f0813 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -150,220 +150,224 @@ getter.a = 12; >getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) >a : Symbol(a, Decl(objectSpread.ts, 32, 13)) -// null and undefined are just skipped -let spreadNull: { a: number } = +// null, undefined, functions and primitives result in { } +let spreadNull = { ...null }; >spreadNull : Symbol(spreadNull, Decl(objectSpread.ts, 37, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 37, 17)) - { a: 7, ...null } ->a : Symbol(a, Decl(objectSpread.ts, 38, 5)) +let spreadUndefind = { ...undefined }; +>spreadUndefind : Symbol(spreadUndefind, Decl(objectSpread.ts, 38, 3)) -let spreadUndefined: { a: number } = ->spreadUndefined : Symbol(spreadUndefined, Decl(objectSpread.ts, 39, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 39, 22)) +let spreadNum = { ...12 }; +>spreadNum : Symbol(spreadNum, Decl(objectSpread.ts, 39, 3)) - { a: 7, ...undefined } ->a : Symbol(a, Decl(objectSpread.ts, 40, 5)) +let spreadStr = { ...'foo' }; +>spreadStr : Symbol(spreadStr, Decl(objectSpread.ts, 40, 3)) + +let spreadBool = { ...false }; +>spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 41, 3)) + +let spreadFunc = { ...(function () { }) }; +>spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 42, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 40, 26)) ->p : Symbol(C.p, Decl(objectSpread.ts, 43, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 43, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 42)) +>p : Symbol(C.p, Decl(objectSpread.ts, 45, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 45, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 44, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 40, 26)) ->C : Symbol(C, Decl(objectSpread.ts, 40, 26)) +>c : Symbol(c, Decl(objectSpread.ts, 46, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 42)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 42)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 45, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 45, 14)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 47, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 47, 14)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 48, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 48, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 48, 23)) ->plus : Symbol(plus, Decl(objectSpread.ts, 48, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 50, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) +>plus : Symbol(plus, Decl(objectSpread.ts, 50, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 48, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 48, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 48, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 52, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 52, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 52, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 54, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 54, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 54, 33)) { ...o, a: 'wrong type?' } ->a : Symbol(a, Decl(objectSpread.ts, 53, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 55, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 54, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 54, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 54, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 56, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 56, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 56, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 55, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 57, 5)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 56, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 56, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 56, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 58, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 58, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 58, 32)) { ...o, ...swap }; // optional let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 60, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 60, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 62, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 62, 22)) let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 61, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 61, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 63, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 62, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 62, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 64, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 63, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 65, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 64, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 64, 25)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 66, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 66, 25)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 65, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 65, 30)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 67, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 67, 30)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 66, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 66, 18)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 68, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 68, 18)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 69, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 69, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 69, 31)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 71, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 71, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 71, 31)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 70, 5)) ->b : Symbol(b, Decl(objectSpread.ts, 70, 38)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 72, 5)) +>b : Symbol(b, Decl(objectSpread.ts, 72, 38)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 71, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 71, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 71, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 71, 43)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 73, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 73, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 73, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 73, 43)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 72, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 72, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 74, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 74, 34)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 73, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 73, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 73, 31)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 75, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 75, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 75, 31)) { ...o, b: 'yeah', ['at the end']: 14 } ->b : Symbol(b, Decl(objectSpread.ts, 74, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 74, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 76, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 76, 22)) // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 76, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 78, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 77, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 77, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 77, 29)) ->a : Symbol(a, Decl(objectSpread.ts, 77, 51)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 79, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 79, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 79, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 79, 51)) // generics function f(t: T, u: U): { id: string, ...T, ...U } { ->f : Symbol(f, Decl(objectSpread.ts, 77, 55)) ->T : Symbol(T, Decl(objectSpread.ts, 80, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 80, 13)) ->t : Symbol(t, Decl(objectSpread.ts, 80, 17)) ->T : Symbol(T, Decl(objectSpread.ts, 80, 11)) ->u : Symbol(u, Decl(objectSpread.ts, 80, 22)) ->U : Symbol(U, Decl(objectSpread.ts, 80, 13)) ->id : Symbol(id, Decl(objectSpread.ts, 80, 31)) ->T : Symbol(T, Decl(objectSpread.ts, 80, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 80, 13)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>T : Symbol(T, Decl(objectSpread.ts, 82, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 82, 13)) +>t : Symbol(t, Decl(objectSpread.ts, 82, 17)) +>T : Symbol(T, Decl(objectSpread.ts, 82, 11)) +>u : Symbol(u, Decl(objectSpread.ts, 82, 22)) +>U : Symbol(U, Decl(objectSpread.ts, 82, 13)) +>id : Symbol(id, Decl(objectSpread.ts, 82, 31)) +>T : Symbol(T, Decl(objectSpread.ts, 82, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 82, 13)) return { id: 'id', ...t, ...u }; ->id : Symbol(id, Decl(objectSpread.ts, 81, 12)) +>id : Symbol(id, Decl(objectSpread.ts, 83, 12)) } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : Symbol(exclusive, Decl(objectSpread.ts, 83, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 83, 16)) ->a : Symbol(a, Decl(objectSpread.ts, 83, 28)) ->b : Symbol(b, Decl(objectSpread.ts, 83, 39)) ->c : Symbol(c, Decl(objectSpread.ts, 83, 50)) ->d : Symbol(d, Decl(objectSpread.ts, 83, 61)) +>exclusive : Symbol(exclusive, Decl(objectSpread.ts, 85, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 85, 16)) +>a : Symbol(a, Decl(objectSpread.ts, 85, 28)) +>b : Symbol(b, Decl(objectSpread.ts, 85, 39)) +>c : Symbol(c, Decl(objectSpread.ts, 85, 50)) +>d : Symbol(d, Decl(objectSpread.ts, 85, 61)) f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f : Symbol(f, Decl(objectSpread.ts, 77, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 84, 7)) ->b : Symbol(b, Decl(objectSpread.ts, 84, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 84, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 84, 36)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 86, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 86, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 86, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 86, 36)) let overlap: { id: string, a: number, b: string } = ->overlap : Symbol(overlap, Decl(objectSpread.ts, 85, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 85, 14)) ->a : Symbol(a, Decl(objectSpread.ts, 85, 26)) ->b : Symbol(b, Decl(objectSpread.ts, 85, 37)) +>overlap : Symbol(overlap, Decl(objectSpread.ts, 87, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 87, 14)) +>a : Symbol(a, Decl(objectSpread.ts, 87, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 87, 37)) f({ a: 1 }, { a: 2, b: 'extra' }) ->f : Symbol(f, Decl(objectSpread.ts, 77, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 86, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 86, 17)) ->b : Symbol(b, Decl(objectSpread.ts, 86, 23)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 88, 23)) let overlapConflict: { id:string, a: string } = ->overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 87, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 87, 22)) ->a : Symbol(a, Decl(objectSpread.ts, 87, 33)) +>overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 89, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 89, 22)) +>a : Symbol(a, Decl(objectSpread.ts, 89, 33)) f({ a: 1 }, { a: 'mismatch' }) ->f : Symbol(f, Decl(objectSpread.ts, 77, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 17)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 17)) let overwriteId: { id: boolean, a: number, c: number, d: string } = ->overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 89, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 89, 18)) ->a : Symbol(a, Decl(objectSpread.ts, 89, 31)) ->c : Symbol(c, Decl(objectSpread.ts, 89, 42)) ->d : Symbol(d, Decl(objectSpread.ts, 89, 53)) +>overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 91, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 91, 18)) +>a : Symbol(a, Decl(objectSpread.ts, 91, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 91, 42)) +>d : Symbol(d, Decl(objectSpread.ts, 91, 53)) f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f : Symbol(f, Decl(objectSpread.ts, 77, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 7)) ->id : Symbol(id, Decl(objectSpread.ts, 90, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 90, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 90, 33)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 92, 7)) +>id : Symbol(id, Decl(objectSpread.ts, 92, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 92, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 92, 33)) class D { m() { }; q = 2; } ->D : Symbol(D, Decl(objectSpread.ts, 90, 44)) ->m : Symbol(D.m, Decl(objectSpread.ts, 92, 9)) ->q : Symbol(D.q, Decl(objectSpread.ts, 92, 18)) +>D : Symbol(D, Decl(objectSpread.ts, 92, 44)) +>m : Symbol(D.m, Decl(objectSpread.ts, 94, 9)) +>q : Symbol(D.q, Decl(objectSpread.ts, 94, 18)) let classesAreWrong: { id: string, ...C, ...D } = ->classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 93, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 93, 22)) ->C : Symbol(C, Decl(objectSpread.ts, 40, 26)) ->D : Symbol(D, Decl(objectSpread.ts, 90, 44)) +>classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 95, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 95, 22)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 42)) +>D : Symbol(D, Decl(objectSpread.ts, 92, 44)) f(new C(), new D()) ->f : Symbol(f, Decl(objectSpread.ts, 77, 55)) ->C : Symbol(C, Decl(objectSpread.ts, 40, 26)) ->D : Symbol(D, Decl(objectSpread.ts, 90, 44)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 42)) +>D : Symbol(D, Decl(objectSpread.ts, 92, 44)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 86d04eb4588be..2b13af1d3d6e7 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -223,27 +223,36 @@ getter.a = 12; >a : number >12 : 12 -// null and undefined are just skipped -let spreadNull: { a: number } = ->spreadNull : { a: number; } ->a : number - - { a: 7, ...null } ->{ a: 7, ...null } : { a: number; } ->a : number ->7 : 7 +// null, undefined, functions and primitives result in { } +let spreadNull = { ...null }; +>spreadNull : {} +>{ ...null } : {} >null : null -let spreadUndefined: { a: number } = ->spreadUndefined : { a: number; } ->a : number - - { a: 7, ...undefined } ->{ a: 7, ...undefined } : { a: number; } ->a : number ->7 : 7 +let spreadUndefind = { ...undefined }; +>spreadUndefind : {} +>{ ...undefined } : {} >undefined : any +let spreadNum = { ...12 }; +>spreadNum : {} +>{ ...12 } : {} + +let spreadStr = { ...'foo' }; +>spreadStr : {} +>{ ...'foo' } : {} + +let spreadBool = { ...false }; +>spreadBool : {} +>{ ...false } : {} +>false : false + +let spreadFunc = { ...(function () { }) }; +>spreadFunc : {} +>{ ...(function () { }) } : {} +>(function () { }) : () => void +>function () { } : () => void + // methods are not enumerable class C { p = 1; m() { } } >C : C diff --git a/tests/baselines/reference/objectSpreadIntersection.js b/tests/baselines/reference/objectSpreadIntersection.js new file mode 100644 index 0000000000000..cb93c54796334 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIntersection.js @@ -0,0 +1,79 @@ +//// [objectSpreadIntersection.ts] +function iteratedUnionIntersection(t: T, u: U, v: V): void { + let tu: T | U; + let uv: U & V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); + let assignable: { id: string, ...(T | U), ...(U & V) } = result; +} +// concrete types work +interface A1 { a: number } +interface A2 { a: string } +let a12: A1 & A2; +let result = { ...a12 }; +let sn: number & string = result.a; +let assignable: { ...(A1 & A2) } = result; + +function tripleIntersection(t: T, u: U, v: V): void { + let tuv: T & U & V; + let result = { id: 'foo', ...tuv }; + let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; + let assignable: { id: string, ...(T & U & V) } = result; +} +function iteratedDoubleIntersection(t: T, u: U, v: V): void { + let tu: T & U; + let uv: U & V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; + let assignable: { id: string, ...(T & U), ...(U & V) } = result; +} +function iteratedIntersectionUnion(t: T, u: U, v: V): void { + let tu: T & U; + let uv: U | V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); + let assignable: { id: string, ...(T & U), ...(U | V) } = result; +} + + + +//// [objectSpreadIntersection.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +function iteratedUnionIntersection(t, u, v) { + var tu; + var uv; + var result = __assign({ id: 'bar' }, tu, uv); + var expected; + var assignable = result; +} +var a12; +var result = __assign({}, a12); +var sn = result.a; +var assignable = result; +function tripleIntersection(t, u, v) { + var tuv; + var result = __assign({ id: 'foo' }, tuv); + var expected = result; + var assignable = result; +} +function iteratedDoubleIntersection(t, u, v) { + var tu; + var uv; + var result = __assign({ id: 'bar' }, tu, uv); + var expected; + var assignable = result; +} +function iteratedIntersectionUnion(t, u, v) { + var tu; + var uv; + var result = __assign({ id: 'bar' }, tu, uv); + var expected; + var assignable = result; +} diff --git a/tests/baselines/reference/objectSpreadIntersection.symbols b/tests/baselines/reference/objectSpreadIntersection.symbols new file mode 100644 index 0000000000000..f45b04a20a51c --- /dev/null +++ b/tests/baselines/reference/objectSpreadIntersection.symbols @@ -0,0 +1,219 @@ +=== tests/cases/conformance/types/spread/objectSpreadIntersection.ts === +function iteratedUnionIntersection(t: T, u: U, v: V): void { +>iteratedUnionIntersection : Symbol(iteratedUnionIntersection, Decl(objectSpreadIntersection.ts, 0, 0)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 0, 44)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 0, 49)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 0, 55)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) + + let tu: T | U; +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 1, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) + + let uv: U & V; +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 2, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) + + let result = { id: 'bar', ...tu, ...uv }; +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 3, 18)) + + let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); +>expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 4, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 20)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 49)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 80)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 103)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) + + let assignable: { id: string, ...(T | U), ...(U & V) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 5, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 5, 21)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) +} +// concrete types work +interface A1 { a: number } +>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 6, 1)) +>a : Symbol(A1.a, Decl(objectSpreadIntersection.ts, 8, 14)) + +interface A2 { a: string } +>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 8, 26)) +>a : Symbol(A2.a, Decl(objectSpreadIntersection.ts, 9, 14)) + +let a12: A1 & A2; +>a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 10, 3)) +>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 6, 1)) +>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 8, 26)) + +let result = { ...a12 }; +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 11, 3)) + +let sn: number & string = result.a; +>sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 12, 3)) +>result.a : Symbol(a, Decl(objectSpreadIntersection.ts, 8, 14), Decl(objectSpreadIntersection.ts, 9, 14)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 11, 3)) +>a : Symbol(a, Decl(objectSpreadIntersection.ts, 8, 14), Decl(objectSpreadIntersection.ts, 9, 14)) + +let assignable: { ...(A1 & A2) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 13, 3)) +>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 6, 1)) +>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 8, 26)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 11, 3)) + +function tripleIntersection(t: T, u: U, v: V): void { +>tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 13, 42)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 15, 37)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 15, 42)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 15, 48)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) + + let tuv: T & U & V; +>tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 16, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) + + let result = { id: 'foo', ...tuv }; +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 17, 18)) + + let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; +>expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 18, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 19)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 42)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 65)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) + + let assignable: { id: string, ...(T & U & V) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 19, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 19, 21)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) +} +function iteratedDoubleIntersection(t: T, u: U, v: V): void { +>iteratedDoubleIntersection : Symbol(iteratedDoubleIntersection, Decl(objectSpreadIntersection.ts, 20, 1)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 21, 45)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 21, 50)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 21, 56)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) + + let tu: T & U; +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 22, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) + + let uv: U & V; +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 23, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) + + let result = { id: 'bar', ...tu, ...uv }; +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 24, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 24, 18)) + + let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; +>expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 25, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 19)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 48)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 77)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 100)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) + + let assignable: { id: string, ...(T & U), ...(U & V) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 26, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 21)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 24, 7)) +} +function iteratedIntersectionUnion(t: T, u: U, v: V): void { +>iteratedIntersectionUnion : Symbol(iteratedIntersectionUnion, Decl(objectSpreadIntersection.ts, 27, 1)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 28, 44)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 28, 49)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 28, 55)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) + + let tu: T & U; +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 29, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) + + let uv: U | V; +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 30, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) + + let result = { id: 'bar', ...tu, ...uv }; +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 31, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 31, 18)) + + let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); +>expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 32, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 20)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 49)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 74)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 103)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) + + let assignable: { id: string, ...(T & U), ...(U | V) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 33, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 21)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 31, 7)) +} + + diff --git a/tests/baselines/reference/objectSpreadIntersection.types b/tests/baselines/reference/objectSpreadIntersection.types new file mode 100644 index 0000000000000..7700d8aa384d3 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIntersection.types @@ -0,0 +1,236 @@ +=== tests/cases/conformance/types/spread/objectSpreadIntersection.ts === +function iteratedUnionIntersection(t: T, u: U, v: V): void { +>iteratedUnionIntersection : (t: T, u: U, v: V) => void +>T : T +>U : U +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + + let tu: T | U; +>tu : T | U +>T : T +>U : U + + let uv: U & V; +>uv : U & V +>U : U +>V : V + + let result = { id: 'bar', ...tu, ...uv }; +>result : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) +>{ id: 'bar', ...tu, ...uv } : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) +>id : string +>'bar' : "bar" +>tu : any +>uv : any + + let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); +>expected : ({ id: string; ...T; ...U } & { id: string; ...T; ...V }) | ({ id: string; ...U } & { id: string; ...U; ...V }) +>id : string +>T : T +>U : U +>id : string +>T : T +>V : V +>id : string +>U : U +>id : string +>U : U +>V : V + + let assignable: { id: string, ...(T | U), ...(U & V) } = result; +>assignable : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) +>id : string +>T : T +>U : U +>U : U +>V : V +>result : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) +} +// concrete types work +interface A1 { a: number } +>A1 : A1 +>a : number + +interface A2 { a: string } +>A2 : A2 +>a : string + +let a12: A1 & A2; +>a12 : A1 & A2 +>A1 : A1 +>A2 : A2 + +let result = { ...a12 }; +>result : { a: number; } & { a: string; } +>{ ...a12 } : { a: number; } & { a: string; } +>a12 : any + +let sn: number & string = result.a; +>sn : number & string +>result.a : number & string +>result : { a: number; } & { a: string; } +>a : number & string + +let assignable: { ...(A1 & A2) } = result; +>assignable : { a: number; } & { a: string; } +>A1 : A1 +>A2 : A2 +>result : { a: number; } & { a: string; } + +function tripleIntersection(t: T, u: U, v: V): void { +>tripleIntersection : (t: T, u: U, v: V) => void +>T : T +>U : U +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + + let tuv: T & U & V; +>tuv : T & U & V +>T : T +>U : U +>V : V + + let result = { id: 'foo', ...tuv }; +>result : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } +>{ id: 'foo', ...tuv } : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } +>id : string +>'foo' : "foo" +>tuv : any + + let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; +>expected : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } +>id : string +>T : T +>id : string +>U : U +>id : string +>V : V +>result : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } + + let assignable: { id: string, ...(T & U & V) } = result; +>assignable : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } +>id : string +>T : T +>U : U +>V : V +>result : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } +} +function iteratedDoubleIntersection(t: T, u: U, v: V): void { +>iteratedDoubleIntersection : (t: T, u: U, v: V) => void +>T : T +>U : U +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + + let tu: T & U; +>tu : T & U +>T : T +>U : U + + let uv: U & V; +>uv : U & V +>U : U +>V : V + + let result = { id: 'bar', ...tu, ...uv }; +>result : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } +>{ id: 'bar', ...tu, ...uv } : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } +>id : string +>'bar' : "bar" +>tu : any +>uv : any + + let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; +>expected : { id: string; ...T; ...U } & { id: string; ...T; ...V } & { id: string; ...U } & { id: string; ...U; ...V } +>id : string +>T : T +>U : U +>id : string +>T : T +>V : V +>id : string +>U : U +>id : string +>U : U +>V : V + + let assignable: { id: string, ...(T & U), ...(U & V) } = result; +>assignable : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } +>id : string +>T : T +>U : U +>U : U +>V : V +>result : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } +} +function iteratedIntersectionUnion(t: T, u: U, v: V): void { +>iteratedIntersectionUnion : (t: T, u: U, v: V) => void +>T : T +>U : U +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + + let tu: T & U; +>tu : T & U +>T : T +>U : U + + let uv: U | V; +>uv : U | V +>U : U +>V : V + + let result = { id: 'bar', ...tu, ...uv }; +>result : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) +>{ id: 'bar', ...tu, ...uv } : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) +>id : string +>'bar' : "bar" +>tu : any +>uv : any + + let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); +>expected : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) +>id : string +>T : T +>U : U +>id : string +>U : U +>id : string +>T : T +>V : V +>id : string +>U : U +>V : V + + let assignable: { id: string, ...(T & U), ...(U | V) } = result; +>assignable : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) +>id : string +>T : T +>U : U +>U : U +>V : V +>result : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) +} + + diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 38e564c3b5d4f..84fb1cc4a76c1 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -5,19 +5,23 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(20,5): error TS2322 Property 'b' is missing in type '{ s: string; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(22,1): error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. Property 's' is missing in type 'Bool'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(26,15): error TS2697: Spread properties must be identifiers, property accesses, or object literals. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(29,36): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(29,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(47,39): error TS2697: Spread properties must be identifiers, property accesses, or object literals. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,36): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,53): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(30,12): error TS2339: Property 'null' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,17): error TS2339: Property 'undefined' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,11): error TS2339: Property 'toFixed' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,11): error TS2339: Property 'toFixed' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,11): error TS2339: Property 'length' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS2339: Property 'charAt' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(55,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(63,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (14 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (18 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -27,8 +31,8 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,12): error TS232 class PublicX { public x: number; } - let o3: { ...PublicX, ...PrivateOptionalX }; - let sn: number = o3.x; // error, x is private + let o2: { ...PublicX, ...PrivateOptionalX }; + let sn: number = o2.x; // error, x is private ~ !!! error TS2339: Property 'x' does not exist on type '{}'. let optionalString: { sn?: string }; @@ -52,14 +56,6 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,12): error TS232 !!! error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. !!! error TS2322: Property 's' is missing in type 'Bool'. - // expressions are not allowed - let o1 = { ...1 + 1 }; - ~~~~~ -!!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. - let o2 = { ...(1 + 1) }; - ~~~~~~~ -!!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. - // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } ~ @@ -68,6 +64,39 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,12): error TS232 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } + // null and undefined are just skipped + let spreadNull = { ...null } + spreadNull.null; + ~~~~ +!!! error TS2339: Property 'null' does not exist on type '{}'. + let spreadUndefined = { ...undefined } + spreadUndefined.undefined; + ~~~~~~~~~ +!!! error TS2339: Property 'undefined' does not exist on type '{}'. + + // primitives and functions are skipped + let spreadNum = { ...12 }; + spreadNum.toFixed(); // error, no methods from number + ~~~~~~~ +!!! error TS2339: Property 'toFixed' does not exist on type '{}'. + let spreadSum = { ...1 + 1 }; + spreadSum.toFixed(); // error, no methods from number + ~~~~~~~ +!!! error TS2339: Property 'toFixed' does not exist on type '{}'. + let spreadStr = { ...'foo' }; + spreadStr.length; // error, no 'length' + ~~~~~~ +!!! error TS2339: Property 'length' does not exist on type '{}'. + spreadStr.charAt(1); // error, no methods either + ~~~~~~ +!!! error TS2339: Property 'charAt' does not exist on type '{}'. + let spreadBool = { ...true }; + spreadBool.valueOf(); // error, what were you thinking? + let spreadFunc = { ...function () { } } + spreadFunc(); // error, no call signature + ~~~~~~~~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. + // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist @@ -90,11 +119,6 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(51,12): error TS232 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. - let publicx: PublicX; - let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions - ~~~~~~~~~~~~ -!!! error TS2697: Spread properties must be identifiers, property accesses, or object literals. - // { ...U } is not assignable to U function override(initial: U, override: U): U { return { ...initial, ...override }; diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 6874380599b61..452ec457e9ae3 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -8,8 +8,8 @@ class PrivateOptionalX { class PublicX { public x: number; } -let o3: { ...PublicX, ...PrivateOptionalX }; -let sn: number = o3.x; // error, x is private +let o2: { ...PublicX, ...PrivateOptionalX }; +let sn: number = o2.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; @@ -22,14 +22,29 @@ let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' let b: Bool; spread = b; // error, missing 's' -// expressions are not allowed -let o1 = { ...1 + 1 }; -let o2 = { ...(1 + 1) }; - // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } +// null and undefined are just skipped +let spreadNull = { ...null } +spreadNull.null; +let spreadUndefined = { ...undefined } +spreadUndefined.undefined; + +// primitives and functions are skipped +let spreadNum = { ...12 }; +spreadNum.toFixed(); // error, no methods from number +let spreadSum = { ...1 + 1 }; +spreadSum.toFixed(); // error, no methods from number +let spreadStr = { ...'foo' }; +spreadStr.length; // error, no 'length' +spreadStr.charAt(1); // error, no methods either +let spreadBool = { ...true }; +spreadBool.valueOf(); // error, what were you thinking? +let spreadFunc = { ...function () { } } +spreadFunc(); // error, no call signature + // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist @@ -44,9 +59,6 @@ let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: numb callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature -let publicx: PublicX; -let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions - // { ...U } is not assignable to U function override(initial: U, override: U): U { return { ...initial, ...override }; @@ -74,8 +86,8 @@ var PublicX = (function () { } return PublicX; }()); -var o3; -var sn = o3.x; // error, x is private +var o2; +var sn = o2.x; // error, x is private var optionalString; var optionalNumber; var allOptional = __assign({}, optionalString, optionalNumber); @@ -84,12 +96,26 @@ var allOptional = __assign({}, optionalString, optionalNumber); var spread = { s: 'foo' }; // error, missing 'b' var b; spread = b; // error, missing 's' -// expressions are not allowed -var o1 = __assign({}, 1 + 1); -var o2 = __assign({}, (1 + 1)); // literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); +// null and undefined are just skipped +var spreadNull = __assign({}, null); +spreadNull.null; +var spreadUndefined = __assign({}, undefined); +spreadUndefined.undefined; +// primitives and functions are skipped +var spreadNum = __assign({}, 12); +spreadNum.toFixed(); // error, no methods from number +var spreadSum = __assign({}, 1 + 1); +spreadSum.toFixed(); // error, no methods from number +var spreadStr = __assign({}, 'foo'); +spreadStr.length; // error, no 'length' +spreadStr.charAt(1); // error, no methods either +var spreadBool = __assign({}, true); +spreadBool.valueOf(); // error, what were you thinking? +var spreadFunc = __assign({}, function () { }); +spreadFunc(); // error, no call signature // write-only properties get skipped var setterOnly = __assign({ set b(bad: number) { } }); setterOnly.b = 12; // error, 'b' does not exist @@ -107,8 +133,6 @@ spreadC.m(); // error 'm' is not in '{ ... c }' var callableConstructableSpread; callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature -var publicx; -var callableSpread = __assign({}, publicx, (function (n) { return n + 1; })); // error, can't spread functions // { ...U } is not assignable to U function override(initial, override) { return __assign({}, initial, override); diff --git a/tests/baselines/reference/objectSpreadUnion.js b/tests/baselines/reference/objectSpreadUnion.js new file mode 100644 index 0000000000000..500b8a5ddc7ca --- /dev/null +++ b/tests/baselines/reference/objectSpreadUnion.js @@ -0,0 +1,52 @@ +//// [objectSpreadUnion.ts] +// concrete types work +interface A1 { a: number } +interface A2 { a: string } +let a12: A1 | A2; +let result = { ...a12 }; +let sn: number | string = result.a; +let assignable: { ...(A1 | A2) } = result; + +function tripleUnion(t: T, u: U, v: V): void { + let tuv: T | U | V; + let result = { id: 'foo', ...tuv }; + let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; + let assignable: { id: string, ...(T | U | V) } = result; +} +function iteratedDoubleUnion(t: T, u: U, v: V): void { + let tu: T | U; + let uv: U | V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; + let assignable: { id: string, ...(T | U), ...(U | V) } = result; +} + + + + +//// [objectSpreadUnion.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var a12; +var result = __assign({}, a12); +var sn = result.a; +var assignable = result; +function tripleUnion(t, u, v) { + var tuv; + var result = __assign({ id: 'foo' }, tuv); + var expected = result; + var assignable = result; +} +function iteratedDoubleUnion(t, u, v) { + var tu; + var uv; + var result = __assign({ id: 'bar' }, tu, uv); + var expected; + var assignable = result; +} diff --git a/tests/baselines/reference/objectSpreadUnion.symbols b/tests/baselines/reference/objectSpreadUnion.symbols new file mode 100644 index 0000000000000..eea9e65185d0a --- /dev/null +++ b/tests/baselines/reference/objectSpreadUnion.symbols @@ -0,0 +1,122 @@ +=== tests/cases/conformance/types/spread/objectSpreadUnion.ts === +// concrete types work +interface A1 { a: number } +>A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0)) +>a : Symbol(A1.a, Decl(objectSpreadUnion.ts, 1, 14)) + +interface A2 { a: string } +>A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26)) +>a : Symbol(A2.a, Decl(objectSpreadUnion.ts, 2, 14)) + +let a12: A1 | A2; +>a12 : Symbol(a12, Decl(objectSpreadUnion.ts, 3, 3)) +>A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0)) +>A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26)) + +let result = { ...a12 }; +>result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3)) + +let sn: number | string = result.a; +>sn : Symbol(sn, Decl(objectSpreadUnion.ts, 5, 3)) +>result.a : Symbol(a, Decl(objectSpreadUnion.ts, 1, 14), Decl(objectSpreadUnion.ts, 2, 14)) +>result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3)) +>a : Symbol(a, Decl(objectSpreadUnion.ts, 1, 14), Decl(objectSpreadUnion.ts, 2, 14)) + +let assignable: { ...(A1 | A2) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 6, 3)) +>A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0)) +>A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26)) +>result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3)) + +function tripleUnion(t: T, u: U, v: V): void { +>tripleUnion : Symbol(tripleUnion, Decl(objectSpreadUnion.ts, 6, 42)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) +>t : Symbol(t, Decl(objectSpreadUnion.ts, 8, 30)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) +>u : Symbol(u, Decl(objectSpreadUnion.ts, 8, 35)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) +>v : Symbol(v, Decl(objectSpreadUnion.ts, 8, 41)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) + + let tuv: T | U | V; +>tuv : Symbol(tuv, Decl(objectSpreadUnion.ts, 9, 7)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) + + let result = { id: 'foo', ...tuv }; +>result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 10, 18)) + + let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; +>expected : Symbol(expected, Decl(objectSpreadUnion.ts, 11, 7)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 19)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 42)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 65)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) +>result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) + + let assignable: { id: string, ...(T | U | V) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 12, 7)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 12, 21)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) +>result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) +} +function iteratedDoubleUnion(t: T, u: U, v: V): void { +>iteratedDoubleUnion : Symbol(iteratedDoubleUnion, Decl(objectSpreadUnion.ts, 13, 1)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) +>t : Symbol(t, Decl(objectSpreadUnion.ts, 14, 38)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) +>u : Symbol(u, Decl(objectSpreadUnion.ts, 14, 43)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>v : Symbol(v, Decl(objectSpreadUnion.ts, 14, 49)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) + + let tu: T | U; +>tu : Symbol(tu, Decl(objectSpreadUnion.ts, 15, 7)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) + + let uv: U | V; +>uv : Symbol(uv, Decl(objectSpreadUnion.ts, 16, 7)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) + + let result = { id: 'bar', ...tu, ...uv }; +>result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 17, 18)) + + let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; +>expected : Symbol(expected, Decl(objectSpreadUnion.ts, 18, 7)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 19)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 48)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 77)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 100)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) + + let assignable: { id: string, ...(T | U), ...(U | V) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 19, 7)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 19, 21)) +>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) +>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) +>result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7)) +} + + + diff --git a/tests/baselines/reference/objectSpreadUnion.types b/tests/baselines/reference/objectSpreadUnion.types new file mode 100644 index 0000000000000..7cbffcf0a584c --- /dev/null +++ b/tests/baselines/reference/objectSpreadUnion.types @@ -0,0 +1,131 @@ +=== tests/cases/conformance/types/spread/objectSpreadUnion.ts === +// concrete types work +interface A1 { a: number } +>A1 : A1 +>a : number + +interface A2 { a: string } +>A2 : A2 +>a : string + +let a12: A1 | A2; +>a12 : A1 | A2 +>A1 : A1 +>A2 : A2 + +let result = { ...a12 }; +>result : { a: number; } | { a: string; } +>{ ...a12 } : { a: number; } | { a: string; } +>a12 : any + +let sn: number | string = result.a; +>sn : string | number +>result.a : string | number +>result : { a: number; } | { a: string; } +>a : string | number + +let assignable: { ...(A1 | A2) } = result; +>assignable : { a: number; } | { a: string; } +>A1 : A1 +>A2 : A2 +>result : { a: number; } | { a: string; } + +function tripleUnion(t: T, u: U, v: V): void { +>tripleUnion : (t: T, u: U, v: V) => void +>T : T +>U : U +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + + let tuv: T | U | V; +>tuv : T | U | V +>T : T +>U : U +>V : V + + let result = { id: 'foo', ...tuv }; +>result : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } +>{ id: 'foo', ...tuv } : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } +>id : string +>'foo' : "foo" +>tuv : any + + let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; +>expected : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } +>id : string +>T : T +>id : string +>U : U +>id : string +>V : V +>result : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } + + let assignable: { id: string, ...(T | U | V) } = result; +>assignable : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } +>id : string +>T : T +>U : U +>V : V +>result : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } +} +function iteratedDoubleUnion(t: T, u: U, v: V): void { +>iteratedDoubleUnion : (t: T, u: U, v: V) => void +>T : T +>U : U +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + + let tu: T | U; +>tu : T | U +>T : T +>U : U + + let uv: U | V; +>uv : U | V +>U : U +>V : V + + let result = { id: 'bar', ...tu, ...uv }; +>result : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } +>{ id: 'bar', ...tu, ...uv } : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } +>id : string +>'bar' : "bar" +>tu : any +>uv : any + + let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; +>expected : { id: string; ...T; ...U } | { id: string; ...T; ...V } | { id: string; ...U } | { id: string; ...U; ...V } +>id : string +>T : T +>U : U +>id : string +>T : T +>V : V +>id : string +>U : U +>id : string +>U : U +>V : V + + let assignable: { id: string, ...(T | U), ...(U | V) } = result; +>assignable : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } +>id : string +>T : T +>U : U +>U : U +>V : V +>result : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } +} + + + diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index 9828e86f0a6bc..e94775649e701 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -35,11 +35,13 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null and undefined are just skipped -let spreadNull: { a: number } = - { a: 7, ...null } -let spreadUndefined: { a: number } = - { a: 7, ...undefined } +// null, undefined, functions and primitives result in { } +let spreadNull = { ...null }; +let spreadUndefind = { ...undefined }; +let spreadNum = { ...12 }; +let spreadStr = { ...'foo' }; +let spreadBool = { ...false }; +let spreadFunc = { ...(function () { }) }; // methods are not enumerable class C { p = 1; m() { } } diff --git a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts new file mode 100644 index 0000000000000..6471e622b68a4 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts @@ -0,0 +1,36 @@ +function iteratedUnionIntersection(t: T, u: U, v: V): void { + let tu: T | U; + let uv: U & V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); + let assignable: { id: string, ...(T | U), ...(U & V) } = result; +} +// concrete types work +interface A1 { a: number } +interface A2 { a: string } +let a12: A1 & A2; +let result = { ...a12 }; +let sn: number & string = result.a; +let assignable: { ...(A1 & A2) } = result; + +function tripleIntersection(t: T, u: U, v: V): void { + let tuv: T & U & V; + let result = { id: 'foo', ...tuv }; + let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; + let assignable: { id: string, ...(T & U & V) } = result; +} +function iteratedDoubleIntersection(t: T, u: U, v: V): void { + let tu: T & U; + let uv: U & V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; + let assignable: { id: string, ...(T & U), ...(U & V) } = result; +} +function iteratedIntersectionUnion(t: T, u: U, v: V): void { + let tu: T & U; + let uv: U | V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); + let assignable: { id: string, ...(T & U), ...(U | V) } = result; +} + diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index d492db4c638b9..04a88d2a42738 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -8,8 +8,8 @@ class PrivateOptionalX { class PublicX { public x: number; } -let o3: { ...PublicX, ...PrivateOptionalX }; -let sn: number = o3.x; // error, x is private +let o2: { ...PublicX, ...PrivateOptionalX }; +let sn: number = o2.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber }; @@ -22,14 +22,29 @@ let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' let b: Bool; spread = b; // error, missing 's' -// expressions are not allowed -let o1 = { ...1 + 1 }; -let o2 = { ...(1 + 1) }; - // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } +// null and undefined are just skipped +let spreadNull = { ...null } +spreadNull.null; +let spreadUndefined = { ...undefined } +spreadUndefined.undefined; + +// primitives and functions are skipped +let spreadNum = { ...12 }; +spreadNum.toFixed(); // error, no methods from number +let spreadSum = { ...1 + 1 }; +spreadSum.toFixed(); // error, no methods from number +let spreadStr = { ...'foo' }; +spreadStr.length; // error, no 'length' +spreadStr.charAt(1); // error, no methods either +let spreadBool = { ...true }; +spreadBool.valueOf(); // error, what were you thinking? +let spreadFunc = { ...function () { } } +spreadFunc(); // error, no call signature + // write-only properties get skipped let setterOnly = { ...{ set b (bad: number) { } } }; setterOnly.b = 12; // error, 'b' does not exist @@ -44,9 +59,6 @@ let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: numb callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature -let publicx: PublicX; -let callableSpread = { ...publicx, ...(n => n + 1) }; // error, can't spread functions - // { ...U } is not assignable to U function override(initial: U, override: U): U { return { ...initial, ...override }; diff --git a/tests/cases/conformance/types/spread/objectSpreadUnion.ts b/tests/cases/conformance/types/spread/objectSpreadUnion.ts new file mode 100644 index 0000000000000..03a4251ca8172 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadUnion.ts @@ -0,0 +1,23 @@ +// concrete types work +interface A1 { a: number } +interface A2 { a: string } +let a12: A1 | A2; +let result = { ...a12 }; +let sn: number | string = result.a; +let assignable: { ...(A1 | A2) } = result; + +function tripleUnion(t: T, u: U, v: V): void { + let tuv: T | U | V; + let result = { id: 'foo', ...tuv }; + let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; + let assignable: { id: string, ...(T | U | V) } = result; +} +function iteratedDoubleUnion(t: T, u: U, v: V): void { + let tu: T | U; + let uv: U | V; + let result = { id: 'bar', ...tu, ...uv }; + let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; + let assignable: { id: string, ...(T | U), ...(U | V) } = result; +} + + From 1b3b35f3e0be5c880c01b262f6731659dc4725dd Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 11 Oct 2016 16:12:57 -0700 Subject: [PATCH 24/85] Type inference for spread types Also: 1. Fix missing spread index signatures in getTypeFromTypeLiteral 2. Spread adjacent object types during spread type creation. --- src/compiler/checker.ts | 129 ++++++++++++++++++++++++++++++---------- 1 file changed, 99 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d8ea29a3819b..93d9c19a71bc7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5715,19 +5715,37 @@ namespace ts { let type: ObjectType; if (isSpread) { let members: Map; + let stringIndexInfo: IndexInfo; + let numberIndexInfo: IndexInfo; const spreads: Type[] = []; for (const member of (node as TypeLiteralNode).members) { if (member.kind === SyntaxKind.SpreadTypeElement) { if (members) { - spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, undefined, undefined)); + spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); members = undefined; + stringIndexInfo = undefined; + numberIndexInfo = undefined; } spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type)); } - else if (member.kind !== SyntaxKind.CallSignature && - member.kind !== SyntaxKind.ConstructSignature && - member.kind !== SyntaxKind.IndexSignature) { - // note that spread types don't include call and construct signatures, and index signatures are resolved later + else if (member.kind === SyntaxKind.IndexSignature) { + const index = member as IndexSignatureDeclaration; + if (index.parameters.length === 1) { + const parameter = index.parameters[0]; + if (parameter && parameter.type) { + const indexInfo = createIndexInfo(index.type ? getTypeFromTypeNode(index.type) : anyType, + (getModifierFlags(index) & ModifierFlags.Readonly) !== 0, index); + if (parameter.type.kind === SyntaxKind.StringKeyword) { + stringIndexInfo = indexInfo; + } + else { + numberIndexInfo = indexInfo; + } + } + } + } + else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) { + // note that spread types don't include call and construct signatures const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); const text = getTextOfPropertyName(member.name); const symbol = createSymbol(flags, text); @@ -5740,8 +5758,8 @@ namespace ts { members[symbol.name] = symbol; } } - if (members) { - spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, undefined, undefined)); + if (members || stringIndexInfo || numberIndexInfo) { + spreads.push(createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); } return getSpreadType(spreads, node.symbol, aliasSymbol, aliasTypeArguments); } @@ -5802,6 +5820,15 @@ namespace ts { // for types like T ... T, just return ... T return left; } + + if (right.flags & TypeFlags.ObjectType && + left.flags & TypeFlags.Spread && + (left as SpreadType).right.flags & TypeFlags.ObjectType) { + // simplify two adjacent object types: T ... { x } ... { y } becomes T ... { x, y } + // Note: left.left is always a spread type. Can we use this fact to avoid calling getSpreadType again? + return getSpreadType([getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments), + (left as SpreadType).left], symbol, aliasSymbol, aliasTypeArguments); + } if (left.flags & TypeFlags.Intersection) { const spreads = map((left as IntersectionType).types, t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); @@ -7991,7 +8018,8 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter || type.flags & TypeFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || - type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); + type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type) || + type.flags & TypeFlags.Spread && couldSpreadContainTypeParameters(type as SpreadType)); } function couldUnionOrIntersectionContainTypeParameters(type: UnionOrIntersectionType): boolean { @@ -8001,6 +8029,11 @@ namespace ts { return type.couldContainTypeParameters; } + function couldSpreadContainTypeParameters(type: SpreadType): boolean { + return !!(type.right.flags & TypeFlags.TypeParameter || + type.left.flags & TypeFlags.Spread && (type.left as SpreadType).right.flags & TypeFlags.TypeParameter); + } + function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((type).types, t => isTypeParameterAtTopLevel(t, typeParameter)); } @@ -8064,6 +8097,16 @@ namespace ts { target = removeTypesFromUnionOrIntersection(target, matchingTypes); } } + if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { + // only the last type parameter is a valid inference site, + // and only if not followed by object literal properties. + if((source as SpreadType).right.flags & TypeFlags.TypeParameter && + (target as SpreadType).right.flags & TypeFlags.TypeParameter) { + inferFromTypes((source as SpreadType).right, (target as SpreadType).right); + } + + return; + } if (target.flags & TypeFlags.TypeParameter) { // If target is a type parameter, make an inference, unless the source type contains // the anyFunctionType (the wildcard type that's used to avoid contextually typing functions). @@ -8140,31 +8183,57 @@ namespace ts { else { source = getApparentType(source); if (source.flags & TypeFlags.ObjectType) { - if (isInProcess(source, target)) { - return; - } - if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { - return; - } - const key = source.id + "," + target.id; - if (visited[key]) { - return; + if (target.flags & TypeFlags.Spread) { + // with an object type as source, a spread target infers to its last type parameter it + // contains, after removing any properties from a object type that precedes the type parameter + // Note that the call to `typeDifference` creates a new anonymous type. + const spread = target as SpreadType; + const parameter = spread.right.flags & TypeFlags.TypeParameter ? spread.right : (spread.left as SpreadType).right; + const object = spread.right.flags & TypeFlags.TypeParameter ? emptyObjectType : spread.right as ResolvedType; + inferFromTypes(getTypeDifference(source, object), parameter); + target = object; } - visited[key] = true; - if (depth === 0) { - sourceStack = []; - targetStack = []; - } - sourceStack[depth] = source; - targetStack[depth] = target; - depth++; - inferFromProperties(source, target); - inferFromSignatures(source, target, SignatureKind.Call); - inferFromSignatures(source, target, SignatureKind.Construct); - inferFromIndexTypes(source, target); - depth--; + inferFromStructure(source, target); + } + } + } + + function inferFromStructure(source: Type, target: Type) { + if (isInProcess(source, target)) { + return; + } + if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { + return; + } + const key = source.id + "," + target.id; + if (visited[key]) { + return; + } + visited[key] = true; + if (depth === 0) { + sourceStack = []; + targetStack = []; + } + sourceStack[depth] = source; + targetStack[depth] = target; + depth++; + inferFromProperties(source, target); + inferFromSignatures(source, target, SignatureKind.Call); + inferFromSignatures(source, target, SignatureKind.Construct); + inferFromIndexTypes(source, target); + depth--; + } + + function getTypeDifference(type: ObjectType, diff: ResolvedType): ResolvedType { + const members = createMap(); + for (const prop of getPropertiesOfObjectType(type)) { + if (!(prop.name in diff.members)) { + members[prop.name] = prop; } } + const stringIndexInfo = getIndexInfoOfType(diff, IndexKind.String) ? undefined : getIndexInfoOfType(type, IndexKind.String); + const numberIndexInfo = getIndexInfoOfType(diff, IndexKind.Number) ? undefined : getIndexInfoOfType(type, IndexKind.Number); + return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } function inferFromProperties(source: Type, target: Type) { From 4bc4a008bbc9c8fdb55e3a2f7bf9e8c2745ed30e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 11 Oct 2016 16:14:47 -0700 Subject: [PATCH 25/85] Test spread type inference+more index signature tests --- .../spread/objectSpreadIndexSignature.ts | 4 ++ .../types/spread/objectSpreadInference.ts | 59 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/cases/conformance/types/spread/objectSpreadInference.ts diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts index d6f9f511c7b9e..daf8e4e63c573 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -18,3 +18,7 @@ interface Indexed2 { } let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; let nb: number | boolean = ii[1001]; + +function f(t: T) { + let i: { ...T, [n: number]: string }; +} diff --git a/tests/cases/conformance/types/spread/objectSpreadInference.ts b/tests/cases/conformance/types/spread/objectSpreadInference.ts new file mode 100644 index 0000000000000..1984193241988 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadInference.ts @@ -0,0 +1,59 @@ +interface Result { + t: T; + u: U; + v: V; +} +declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; +declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; +function generic(w: W, x: X, y: Y) { + // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter + return infer({ ...w, ...x, a: y, b: "different type" }); +} +let b: { b: number }; +let c: { c: number }; +// should infer { t: {}, u: { b: number, c: number }, v: number } +let i1 = infer({ ...b, ...c, a: 12 }); +// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +let i2 = infer2({ ...b, ...c, a: 12 }); +// should infer { t: {}, u: {}, v: {} } +let i3 = generic(b, c, { a: 12 }); + +interface Preserved { + kind: 0 | 1 | 2 | 3; +} +class C implements Preserved { + kind: 0 = 0; + a = 1; + method() { return "C"; } +} +declare function revive(t: { ...T }): T; +function genericRevive(u: U) { + let us: { ...U }; + return revive(us); +} +// result should not have `method` +let result = revive({ a: 12, kind: 0 }); +// result2 should be of type C and have `method` +let result2 = revive({ a: 12, kind: 0 }); + +declare function destructureRevive(t: { ...T, a: number }): T; +function genericDestructureRevive(u: U) { + let us: { ...U }; + return destructureRevive(us); +} +// result3 is just `Preserved` because `a` and `method` both get removed +let result3 = destructureRevive({ a: 12, kind: 0 }); +// result4 is still C -- a is not removed -- because we specified the argument explicitly +let result4 = destructureRevive({ a: 12, kind: 0 }); +result4.method(); +result4.a; + +declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; +interface I { + a: number; + b: number; + [s: string]: number; + [n: number]: number; +} +let i: I; +let result5 = removeIndexSignature(i); From 7417af6f15cb0abfd547932378f78250d92838d0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 11 Oct 2016 16:15:37 -0700 Subject: [PATCH 26/85] Update baselines --- .../reference/objectSpreadIndexSignature.js | 7 + .../objectSpreadIndexSignature.symbols | 12 + .../objectSpreadIndexSignature.types | 18 +- .../reference/objectSpreadInference.js | 111 +++++++ .../reference/objectSpreadInference.symbols | 241 +++++++++++++++ .../reference/objectSpreadInference.types | 282 ++++++++++++++++++ 6 files changed, 668 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/objectSpreadInference.js create mode 100644 tests/baselines/reference/objectSpreadInference.symbols create mode 100644 tests/baselines/reference/objectSpreadInference.types diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js index b5ec35277e0c3..709cd9446d8da 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.js +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -19,6 +19,10 @@ interface Indexed2 { } let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; let nb: number | boolean = ii[1001]; + +function f(t: T) { + let i: { ...T, [n: number]: string }; +} //// [objectSpreadIndexSignature.js] @@ -35,3 +39,6 @@ n = i[101]; n = i.b; var ii; var nb = ii[1001]; +function f(t) { + var i; +} diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols index a3510f9865830..e76ad3e1b1362 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.symbols +++ b/tests/baselines/reference/objectSpreadIndexSignature.symbols @@ -69,3 +69,15 @@ let nb: number | boolean = ii[1001]; >nb : Symbol(nb, Decl(objectSpreadIndexSignature.ts, 19, 3)) >ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 18, 3)) +function f(t: T) { +>f : Symbol(f, Decl(objectSpreadIndexSignature.ts, 19, 36)) +>T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 21, 11)) +>t : Symbol(t, Decl(objectSpreadIndexSignature.ts, 21, 14)) +>T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 21, 11)) + + let i: { ...T, [n: number]: string }; +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 22, 7)) +>T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 21, 11)) +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 22, 20)) +} + diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types index 6e9ba881db1fb..f646361765d4b 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -9,7 +9,7 @@ class C { >c : boolean } let c: { ...C, b: string, c?: string, [n: number]: string }; ->c : { [n: number]: string; b: string; c: string | boolean; a: number; } +>c : { [x: number]: string; b: string; c: string | boolean; a: number; } >C : C >b : string >c : string @@ -18,13 +18,13 @@ let c: { ...C, b: string, c?: string, [n: number]: string }; let n: number = c.a; >n : number >c.a : number ->c : { [n: number]: string; b: string; c: string | boolean; a: number; } +>c : { [x: number]: string; b: string; c: string | boolean; a: number; } >a : number let s: string = c[12]; >s : string >c[12] : string ->c : { [n: number]: string; b: string; c: string | boolean; a: number; } +>c : { [x: number]: string; b: string; c: string | boolean; a: number; } >12 : 12 interface Indexed { @@ -77,3 +77,15 @@ let nb: number | boolean = ii[1001]; >ii : { [x: string]: number | boolean; b: boolean; d: number; c: boolean; a: number; } >1001 : 1001 +function f(t: T) { +>f : (t: T) => void +>T : T +>t : T +>T : T + + let i: { ...T, [n: number]: string }; +>i : { ...T; [n: number]: string; } +>T : T +>n : number +} + diff --git a/tests/baselines/reference/objectSpreadInference.js b/tests/baselines/reference/objectSpreadInference.js new file mode 100644 index 0000000000000..06b17cfa1f948 --- /dev/null +++ b/tests/baselines/reference/objectSpreadInference.js @@ -0,0 +1,111 @@ +//// [objectSpreadInference.ts] +interface Result { + t: T; + u: U; + v: V; +} +declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; +declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; +function generic(w: W, x: X, y: Y) { + // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter + return infer({ ...w, ...x, a: y, b: "different type" }); +} +let b: { b: number }; +let c: { c: number }; +// should infer { t: {}, u: { b: number, c: number }, v: number } +let i1 = infer({ ...b, ...c, a: 12 }); +// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +let i2 = infer2({ ...b, ...c, a: 12 }); +// should infer { t: {}, u: {}, v: {} } +let i3 = generic(b, c, { a: 12 }); + +interface Preserved { + kind: 0 | 1 | 2 | 3; +} +class C implements Preserved { + kind: 0 = 0; + a = 1; + method() { return "C"; } +} +declare function revive(t: { ...T }): T; +function genericRevive(u: U) { + let us: { ...U }; + return revive(us); +} +// result should not have `method` +let result = revive({ a: 12, kind: 0 }); +// result2 should be of type C and have `method` +let result2 = revive({ a: 12, kind: 0 }); + +declare function destructureRevive(t: { ...T, a: number }): T; +function genericDestructureRevive(u: U) { + let us: { ...U }; + return destructureRevive(us); +} +// result3 is just `Preserved` because `a` and `method` both get removed +let result3 = destructureRevive({ a: 12, kind: 0 }); +// result4 is still C -- a is not removed -- because we specified the argument explicitly +let result4 = destructureRevive({ a: 12, kind: 0 }); +result4.method(); +result4.a; + +declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; +interface I { + a: number; + b: number; + [s: string]: number; + [n: number]: number; +} +let i: I; +let result5 = removeIndexSignature(i); + + +//// [objectSpreadInference.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +function generic(w, x, y) { + // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter + return infer(__assign({}, w, x, { a: y, b: "different type" })); +} +var b; +var c; +// should infer { t: {}, u: { b: number, c: number }, v: number } +var i1 = infer(__assign({}, b, c, { a: 12 })); +// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +var i2 = infer2(__assign({}, b, c, { a: 12 })); +// should infer { t: {}, u: {}, v: {} } +var i3 = generic(b, c, { a: 12 }); +var C = (function () { + function C() { + this.kind = 0; + this.a = 1; + } + C.prototype.method = function () { return "C"; }; + return C; +}()); +function genericRevive(u) { + var us; + return revive(us); +} +// result should not have `method` +var result = revive({ a: 12, kind: 0 }); +// result2 should be of type C and have `method` +var result2 = revive({ a: 12, kind: 0 }); +function genericDestructureRevive(u) { + var us; + return destructureRevive(us); +} +// result3 is just `Preserved` because `a` and `method` both get removed +var result3 = destructureRevive({ a: 12, kind: 0 }); +// result4 is still C -- a is not removed -- because we specified the argument explicitly +var result4 = destructureRevive({ a: 12, kind: 0 }); +result4.method(); +result4.a; +var i; +var result5 = removeIndexSignature(i); diff --git a/tests/baselines/reference/objectSpreadInference.symbols b/tests/baselines/reference/objectSpreadInference.symbols new file mode 100644 index 0000000000000..f03cd6b44e11a --- /dev/null +++ b/tests/baselines/reference/objectSpreadInference.symbols @@ -0,0 +1,241 @@ +=== tests/cases/conformance/types/spread/objectSpreadInference.ts === +interface Result { +>Result : Symbol(Result, Decl(objectSpreadInference.ts, 0, 0)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 0, 17)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 0, 19)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 0, 21)) + + t: T; +>t : Symbol(Result.t, Decl(objectSpreadInference.ts, 0, 25)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 0, 17)) + + u: U; +>u : Symbol(Result.u, Decl(objectSpreadInference.ts, 1, 9)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 0, 19)) + + v: V; +>v : Symbol(Result.v, Decl(objectSpreadInference.ts, 2, 9)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 0, 21)) +} +declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; +>infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27)) +>tuv : Symbol(tuv, Decl(objectSpreadInference.ts, 5, 30)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 5, 48)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 5, 59)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23)) +>u : Symbol(u, Decl(objectSpreadInference.ts, 5, 65)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25)) +>v : Symbol(v, Decl(objectSpreadInference.ts, 5, 71)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27)) + +declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; +>infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28)) +>utv : Symbol(utv, Decl(objectSpreadInference.ts, 6, 31)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 6, 43)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 6, 60)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24)) +>u : Symbol(u, Decl(objectSpreadInference.ts, 6, 66)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26)) +>v : Symbol(v, Decl(objectSpreadInference.ts, 6, 72)) +>V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28)) + +function generic(w: W, x: X, y: Y) { +>generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80)) +>W : Symbol(W, Decl(objectSpreadInference.ts, 7, 17)) +>X : Symbol(X, Decl(objectSpreadInference.ts, 7, 19)) +>Y : Symbol(Y, Decl(objectSpreadInference.ts, 7, 22)) +>w : Symbol(w, Decl(objectSpreadInference.ts, 7, 26)) +>W : Symbol(W, Decl(objectSpreadInference.ts, 7, 17)) +>x : Symbol(x, Decl(objectSpreadInference.ts, 7, 31)) +>X : Symbol(X, Decl(objectSpreadInference.ts, 7, 19)) +>y : Symbol(y, Decl(objectSpreadInference.ts, 7, 37)) +>Y : Symbol(Y, Decl(objectSpreadInference.ts, 7, 22)) + + // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter + return infer({ ...w, ...x, a: y, b: "different type" }); +>infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 9, 30)) +>y : Symbol(y, Decl(objectSpreadInference.ts, 7, 37)) +>b : Symbol(b, Decl(objectSpreadInference.ts, 9, 36)) +} +let b: { b: number }; +>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3)) +>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 8)) + +let c: { c: number }; +>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) +>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 8)) + +// should infer { t: {}, u: { b: number, c: number }, v: number } +let i1 = infer({ ...b, ...c, a: 12 }); +>i1 : Symbol(i1, Decl(objectSpreadInference.ts, 14, 3)) +>infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 14, 28)) + +// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +let i2 = infer2({ ...b, ...c, a: 12 }); +>i2 : Symbol(i2, Decl(objectSpreadInference.ts, 16, 3)) +>infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 16, 29)) + +// should infer { t: {}, u: {}, v: {} } +let i3 = generic(b, c, { a: 12 }); +>i3 : Symbol(i3, Decl(objectSpreadInference.ts, 18, 3)) +>generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80)) +>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3)) +>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 18, 24)) + +interface Preserved { +>Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) + + kind: 0 | 1 | 2 | 3; +>kind : Symbol(Preserved.kind, Decl(objectSpreadInference.ts, 20, 21)) +} +class C implements Preserved { +>C : Symbol(C, Decl(objectSpreadInference.ts, 22, 1)) +>Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) + + kind: 0 = 0; +>kind : Symbol(C.kind, Decl(objectSpreadInference.ts, 23, 30)) + + a = 1; +>a : Symbol(C.a, Decl(objectSpreadInference.ts, 24, 16)) + + method() { return "C"; } +>method : Symbol(C.method, Decl(objectSpreadInference.ts, 25, 10)) +} +declare function revive(t: { ...T }): T; +>revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 28, 24)) +>Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 28, 45)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 28, 24)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 28, 24)) + +function genericRevive(u: U) { +>genericRevive : Symbol(genericRevive, Decl(objectSpreadInference.ts, 28, 61)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 29, 23)) +>Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) +>u : Symbol(u, Decl(objectSpreadInference.ts, 29, 44)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 29, 23)) + + let us: { ...U }; +>us : Symbol(us, Decl(objectSpreadInference.ts, 30, 7)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 29, 23)) + + return revive(us); +>revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) +>us : Symbol(us, Decl(objectSpreadInference.ts, 30, 7)) +} +// result should not have `method` +let result = revive({ a: 12, kind: 0 }); +>result : Symbol(result, Decl(objectSpreadInference.ts, 34, 3)) +>revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 34, 21)) +>kind : Symbol(kind, Decl(objectSpreadInference.ts, 34, 28)) + +// result2 should be of type C and have `method` +let result2 = revive({ a: 12, kind: 0 }); +>result2 : Symbol(result2, Decl(objectSpreadInference.ts, 36, 3)) +>revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) +>C : Symbol(C, Decl(objectSpreadInference.ts, 22, 1)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 36, 25)) +>kind : Symbol(kind, Decl(objectSpreadInference.ts, 36, 32)) + +declare function destructureRevive(t: { ...T, a: number }): T; +>destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 38, 35)) +>Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 38, 56)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 38, 35)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 38, 66)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 38, 35)) + +function genericDestructureRevive(u: U) { +>genericDestructureRevive : Symbol(genericDestructureRevive, Decl(objectSpreadInference.ts, 38, 83)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 39, 34)) +>Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 39, 57)) +>u : Symbol(u, Decl(objectSpreadInference.ts, 39, 71)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 39, 34)) + + let us: { ...U }; +>us : Symbol(us, Decl(objectSpreadInference.ts, 40, 7)) +>U : Symbol(U, Decl(objectSpreadInference.ts, 39, 34)) + + return destructureRevive(us); +>destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) +>us : Symbol(us, Decl(objectSpreadInference.ts, 40, 7)) +} +// result3 is just `Preserved` because `a` and `method` both get removed +let result3 = destructureRevive({ a: 12, kind: 0 }); +>result3 : Symbol(result3, Decl(objectSpreadInference.ts, 44, 3)) +>destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 44, 33)) +>kind : Symbol(kind, Decl(objectSpreadInference.ts, 44, 40)) + +// result4 is still C -- a is not removed -- because we specified the argument explicitly +let result4 = destructureRevive({ a: 12, kind: 0 }); +>result4 : Symbol(result4, Decl(objectSpreadInference.ts, 46, 3)) +>destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) +>C : Symbol(C, Decl(objectSpreadInference.ts, 22, 1)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 46, 36)) +>kind : Symbol(kind, Decl(objectSpreadInference.ts, 46, 43)) + +result4.method(); +>result4.method : Symbol(C.method, Decl(objectSpreadInference.ts, 25, 10)) +>result4 : Symbol(result4, Decl(objectSpreadInference.ts, 46, 3)) +>method : Symbol(C.method, Decl(objectSpreadInference.ts, 25, 10)) + +result4.a; +>result4.a : Symbol(C.a, Decl(objectSpreadInference.ts, 24, 16)) +>result4 : Symbol(result4, Decl(objectSpreadInference.ts, 46, 3)) +>a : Symbol(C.a, Decl(objectSpreadInference.ts, 24, 16)) + +declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; +>removeIndexSignature : Symbol(removeIndexSignature, Decl(objectSpreadInference.ts, 48, 10)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 50, 38)) +>t : Symbol(t, Decl(objectSpreadInference.ts, 50, 41)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 50, 38)) +>a : Symbol(a, Decl(objectSpreadInference.ts, 50, 51)) +>s : Symbol(s, Decl(objectSpreadInference.ts, 50, 64)) +>n : Symbol(n, Decl(objectSpreadInference.ts, 50, 85)) +>T : Symbol(T, Decl(objectSpreadInference.ts, 50, 38)) + +interface I { +>I : Symbol(I, Decl(objectSpreadInference.ts, 50, 110)) + + a: number; +>a : Symbol(I.a, Decl(objectSpreadInference.ts, 51, 13)) + + b: number; +>b : Symbol(I.b, Decl(objectSpreadInference.ts, 52, 14)) + + [s: string]: number; +>s : Symbol(s, Decl(objectSpreadInference.ts, 54, 5)) + + [n: number]: number; +>n : Symbol(n, Decl(objectSpreadInference.ts, 55, 5)) +} +let i: I; +>i : Symbol(i, Decl(objectSpreadInference.ts, 57, 3)) +>I : Symbol(I, Decl(objectSpreadInference.ts, 50, 110)) + +let result5 = removeIndexSignature(i); +>result5 : Symbol(result5, Decl(objectSpreadInference.ts, 58, 3)) +>removeIndexSignature : Symbol(removeIndexSignature, Decl(objectSpreadInference.ts, 48, 10)) +>i : Symbol(i, Decl(objectSpreadInference.ts, 57, 3)) + diff --git a/tests/baselines/reference/objectSpreadInference.types b/tests/baselines/reference/objectSpreadInference.types new file mode 100644 index 0000000000000..55303119932e1 --- /dev/null +++ b/tests/baselines/reference/objectSpreadInference.types @@ -0,0 +1,282 @@ +=== tests/cases/conformance/types/spread/objectSpreadInference.ts === +interface Result { +>Result : Result +>T : T +>U : U +>V : V + + t: T; +>t : T +>T : T + + u: U; +>u : U +>U : U + + v: V; +>v : V +>V : V +} +declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; +>infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } +>T : T +>U : U +>V : V +>tuv : { ...T; ...U; a: V; } +>T : T +>U : U +>a : V +>V : V +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + +declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; +>infer2 : (utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; } +>T : T +>U : U +>V : V +>utv : { ...U; a: V; ...T } +>U : U +>a : V +>V : V +>T : T +>t : T +>T : T +>u : U +>U : U +>v : V +>V : V + +function generic(w: W, x: X, y: Y) { +>generic : (w: W, x: X, y: Y) => { t: {}; u: {}; v: {}; } +>W : W +>X : X +>Y : Y +>w : W +>W : W +>x : X +>X : X +>y : Y +>Y : Y + + // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter + return infer({ ...w, ...x, a: y, b: "different type" }); +>infer({ ...w, ...x, a: y, b: "different type" }) : { t: {}; u: {}; v: {}; } +>infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } +>{ ...w, ...x, a: y, b: "different type" } : { ...W; ...X; a: Y; b: string; } +>w : any +>x : any +>a : Y +>y : Y +>b : string +>"different type" : "different type" +} +let b: { b: number }; +>b : { b: number; } +>b : number + +let c: { c: number }; +>c : { c: number; } +>c : number + +// should infer { t: {}, u: { b: number, c: number }, v: number } +let i1 = infer({ ...b, ...c, a: 12 }); +>i1 : { t: {}; u: { c: number; b: number; }; v: number; } +>infer({ ...b, ...c, a: 12 }) : { t: {}; u: { c: number; b: number; }; v: number; } +>infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } +>{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; } +>b : any +>c : any +>a : number +>12 : 12 + +// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +let i2 = infer2({ ...b, ...c, a: 12 }); +>i2 : { t: { a: number; c: number; b: number; }; u: {}; v: {}; } +>infer2({ ...b, ...c, a: 12 }) : { t: { a: number; c: number; b: number; }; u: {}; v: {}; } +>infer2 : (utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; } +>{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; } +>b : any +>c : any +>a : number +>12 : 12 + +// should infer { t: {}, u: {}, v: {} } +let i3 = generic(b, c, { a: 12 }); +>i3 : { t: {}; u: {}; v: {}; } +>generic(b, c, { a: 12 }) : { t: {}; u: {}; v: {}; } +>generic : (w: W, x: X, y: Y) => { t: {}; u: {}; v: {}; } +>b : { b: number; } +>c : { c: number; } +>{ a: 12 } : { a: number; } +>a : number +>12 : 12 + +interface Preserved { +>Preserved : Preserved + + kind: 0 | 1 | 2 | 3; +>kind : 0 | 1 | 2 | 3 +} +class C implements Preserved { +>C : C +>Preserved : Preserved + + kind: 0 = 0; +>kind : 0 +>0 : 0 + + a = 1; +>a : number +>1 : 1 + + method() { return "C"; } +>method : () => string +>"C" : "C" +} +declare function revive(t: { ...T }): T; +>revive : (t: { ...T }) => T +>T : T +>Preserved : Preserved +>t : { ...T } +>T : T +>T : T + +function genericRevive(u: U) { +>genericRevive : (u: U) => U +>U : U +>Preserved : Preserved +>u : U +>U : U + + let us: { ...U }; +>us : { ...U } +>U : U + + return revive(us); +>revive(us) : U +>revive : (t: { ...T }) => T +>us : { ...U } +} +// result should not have `method` +let result = revive({ a: 12, kind: 0 }); +>result : { a: number; kind: 0; } +>revive({ a: 12, kind: 0 }) : { a: number; kind: 0; } +>revive : (t: { ...T }) => T +>{ a: 12, kind: 0 } : { a: number; kind: 0; } +>a : number +>12 : 12 +>kind : number +>0 : 0 + +// result2 should be of type C and have `method` +let result2 = revive({ a: 12, kind: 0 }); +>result2 : C +>revive({ a: 12, kind: 0 }) : C +>revive : (t: { ...T }) => T +>C : C +>{ a: 12, kind: 0 } : { a: number; kind: 0; } +>a : number +>12 : 12 +>kind : number +>0 : 0 + +declare function destructureRevive(t: { ...T, a: number }): T; +>destructureRevive : (t: { ...T; a: number; }) => T +>T : T +>Preserved : Preserved +>t : { ...T; a: number; } +>T : T +>a : number +>T : T + +function genericDestructureRevive(u: U) { +>genericDestructureRevive : (u: U) => Preserved +>U : U +>Preserved : Preserved +>a : number +>u : U +>U : U + + let us: { ...U }; +>us : { ...U } +>U : U + + return destructureRevive(us); +>destructureRevive(us) : Preserved +>destructureRevive : (t: { ...T; a: number; }) => T +>us : { ...U } +} +// result3 is just `Preserved` because `a` and `method` both get removed +let result3 = destructureRevive({ a: 12, kind: 0 }); +>result3 : { kind: 0; } +>destructureRevive({ a: 12, kind: 0 }) : { kind: 0; } +>destructureRevive : (t: { ...T; a: number; }) => T +>{ a: 12, kind: 0 } : { a: number; kind: 0; } +>a : number +>12 : 12 +>kind : number +>0 : 0 + +// result4 is still C -- a is not removed -- because we specified the argument explicitly +let result4 = destructureRevive({ a: 12, kind: 0 }); +>result4 : C +>destructureRevive({ a: 12, kind: 0 }) : C +>destructureRevive : (t: { ...T; a: number; }) => T +>C : C +>{ a: 12, kind: 0 } : { a: number; kind: 0; } +>a : number +>12 : 12 +>kind : number +>0 : 0 + +result4.method(); +>result4.method() : string +>result4.method : () => string +>result4 : C +>method : () => string + +result4.a; +>result4.a : number +>result4 : C +>a : number + +declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; +>removeIndexSignature : (t: { ...T; [s: string]: number; [n: number]: number; a: number; }) => T +>T : T +>t : { ...T; [s: string]: number; [n: number]: number; a: number; } +>T : T +>a : number +>s : string +>n : number +>T : T + +interface I { +>I : I + + a: number; +>a : number + + b: number; +>b : number + + [s: string]: number; +>s : string + + [n: number]: number; +>n : number +} +let i: I; +>i : I +>I : I + +let result5 = removeIndexSignature(i); +>result5 : { b: number; } +>removeIndexSignature(i) : { b: number; } +>removeIndexSignature : (t: { ...T; [s: string]: number; [n: number]: number; a: number; }) => T +>i : I + From ce373d904a0dc6abd79736ac8bac12af647f8572 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 11 Oct 2016 16:16:36 -0700 Subject: [PATCH 27/85] Revert lib.d.ts error message baseline (unrelated) It should fixed in a separate PR. --- .../reference/variableDeclarationInStrictMode1.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index 46782aaa1d69d..c47ac71f74869 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -1,4 +1,4 @@ -lib.d.ts(32,18): error TS2300: Duplicate identifier 'eval'. +lib.d.ts(28,18): error TS2300: Duplicate identifier 'eval'. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS1100: Invalid use of 'eval' in strict mode. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Duplicate identifier 'eval'. @@ -9,4 +9,4 @@ tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Dup ~~~~ !!! error TS1100: Invalid use of 'eval' in strict mode. ~~~~ -!!! error TS2300: Duplicate identifier 'eval'. \ No newline at end of file +!!! error TS2300: Duplicate identifier 'eval'. From 97dda6e0eb8568871cb38ede8cd90303beb7cade Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 08:40:08 -0700 Subject: [PATCH 28/85] Remove emacs-added newline at end of baseline --- .../reference/variableDeclarationInStrictMode1.errors.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index c47ac71f74869..15c79179f70fd 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -9,4 +9,4 @@ tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Dup ~~~~ !!! error TS1100: Invalid use of 'eval' in strict mode. ~~~~ -!!! error TS2300: Duplicate identifier 'eval'. +!!! error TS2300: Duplicate identifier 'eval'. \ No newline at end of file From c5228d3435b3b7d528520f74735e354559879574 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 08:58:49 -0700 Subject: [PATCH 29/85] Remove space at end of line in baseline --- .../reference/variableDeclarationInStrictMode1.errors.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index 15c79179f70fd..9dd9a8d41a1bf 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -9,4 +9,4 @@ tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Dup ~~~~ !!! error TS1100: Invalid use of 'eval' in strict mode. ~~~~ -!!! error TS2300: Duplicate identifier 'eval'. \ No newline at end of file +!!! error TS2300: Duplicate identifier 'eval'. \ No newline at end of file From 5a037ad36867b5b5f8aad51bb12e9dd18005cf99 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 09:00:17 -0700 Subject: [PATCH 30/85] Add numeric indexer to strings and remove lint --- src/compiler/checker.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 93d9c19a71bc7..bfd6d78e89164 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5781,7 +5781,10 @@ namespace ts { if (id in spreadTypes) { return spreadTypes[id]; } - const right = types.pop(); + let right = types.pop(); + if (right.flags & TypeFlags.StringLike) { + right = createAnonymousType(symbol, emptySymbols, emptyArray, emptyArray, undefined, createIndexInfo(stringType, /*isReadonly*/ false)); + } if (right.flags & TypeFlags.Any) { return anyType; } @@ -5801,16 +5804,13 @@ namespace ts { return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments); } if (right.flags & TypeFlags.Union) { - // TODO: types is mutable, so this block has to happen before the call to `const left = getSpreadType(...)` - // because that call consumes the array. It might be worthwhile to use a simple linked list here instead. - // It would avoid the slice+concat call that is needed here for multiple calls to getSpreadType. const spreads = map((right as UnionType).types, t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } const atBeginning = types.length === 0; const left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); - if (right.flags & TypeFlags.Primitive || left.flags & TypeFlags.Any) { + if (right.flags & (TypeFlags.Primitive & ~TypeFlags.StringLike) || left.flags & TypeFlags.Any) { return left; } if (right.flags & TypeFlags.TypeParameter && @@ -5837,7 +5837,7 @@ namespace ts { if (left.flags & TypeFlags.Union) { const spreads = map((left as UnionType).types, t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); - return getUnionType(spreads, /*subTypeReduction*/ false, aliasSymbol, aliasTypeArguments); + return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } if (right.flags & TypeFlags.ObjectType && left.flags & TypeFlags.ObjectType) { const members = createMap(); @@ -8100,7 +8100,7 @@ namespace ts { if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { // only the last type parameter is a valid inference site, // and only if not followed by object literal properties. - if((source as SpreadType).right.flags & TypeFlags.TypeParameter && + if ((source as SpreadType).right.flags & TypeFlags.TypeParameter && (target as SpreadType).right.flags & TypeFlags.TypeParameter) { inferFromTypes((source as SpreadType).right, (target as SpreadType).right); } @@ -19053,7 +19053,6 @@ namespace ts { function getRootSymbols(symbol: Symbol): Symbol[] { if (symbol.flags & SymbolFlags.SyntheticProperty) { if (symbol.syntheticKind === SyntheticSymbolKind.Spread) { - const name = symbol.name; const links = getSymbolLinks(symbol); return [links.leftSpread, links.rightSpread]; } From 1728ae1cbc0d454e6e47292e22dd6a6d885f74fa Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 09:01:14 -0700 Subject: [PATCH 31/85] Update baselines with spread string's numeric indexers --- tests/baselines/reference/objectSpread.js | 11 +- .../baselines/reference/objectSpread.symbols | 247 +++++++++--------- tests/baselines/reference/objectSpread.types | 11 +- .../reference/objectSpreadNegative.errors.txt | 8 +- ...ariableDeclarationInStrictMode1.errors.txt | 2 +- .../conformance/types/spread/objectSpread.ts | 6 +- 6 files changed, 146 insertions(+), 139 deletions(-) diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index a09f5aa0fbb1a..efb73bcb35399 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -35,14 +35,16 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null, undefined, functions and primitives result in { } +// null, undefined, functions and primitives besides string result in { } let spreadNull = { ...null }; let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; -let spreadStr = { ...'foo' }; let spreadBool = { ...false }; let spreadFunc = { ...(function () { }) }; +// strings get a numeric indexer: [n: number]: string +let spreadStr = { ...'foo' }; + // methods are not enumerable class C { p = 1; m() { } } let c: C = new C() @@ -128,13 +130,14 @@ var propertyNested = __assign({ a: __assign({}, o) }); var op = { get a() { return 6; } }; var getter = __assign({}, op, { c: 7 }); getter.a = 12; -// null, undefined, functions and primitives result in { } +// null, undefined, functions and primitives besides string result in { } var spreadNull = __assign({}, null); var spreadUndefind = __assign({}, undefined); var spreadNum = __assign({}, 12); -var spreadStr = __assign({}, 'foo'); var spreadBool = __assign({}, false); var spreadFunc = __assign({}, (function () { })); +// strings get a numeric indexer: [n: number]: string +var spreadStr = __assign({}, 'foo'); // methods are not enumerable var C = (function () { function C() { diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index edb0b4c2f0813..d23016ddb1e15 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -150,7 +150,7 @@ getter.a = 12; >getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) >a : Symbol(a, Decl(objectSpread.ts, 32, 13)) -// null, undefined, functions and primitives result in { } +// null, undefined, functions and primitives besides string result in { } let spreadNull = { ...null }; >spreadNull : Symbol(spreadNull, Decl(objectSpread.ts, 37, 3)) @@ -160,214 +160,215 @@ let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; >spreadNum : Symbol(spreadNum, Decl(objectSpread.ts, 39, 3)) -let spreadStr = { ...'foo' }; ->spreadStr : Symbol(spreadStr, Decl(objectSpread.ts, 40, 3)) - let spreadBool = { ...false }; ->spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 41, 3)) +>spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 40, 3)) let spreadFunc = { ...(function () { }) }; ->spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 42, 3)) +>spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 41, 3)) + +// strings get a numeric indexer: [n: number]: string +let spreadStr = { ...'foo' }; +>spreadStr : Symbol(spreadStr, Decl(objectSpread.ts, 44, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 42, 42)) ->p : Symbol(C.p, Decl(objectSpread.ts, 45, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 45, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 29)) +>p : Symbol(C.p, Decl(objectSpread.ts, 47, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 47, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 46, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 42)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 42)) +>c : Symbol(c, Decl(objectSpread.ts, 48, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 29)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 29)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 47, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 47, 14)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 49, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 49, 14)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 50, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) ->plus : Symbol(plus, Decl(objectSpread.ts, 50, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 52, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 52, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) +>plus : Symbol(plus, Decl(objectSpread.ts, 52, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 52, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 54, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 54, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 54, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 56, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 56, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 56, 33)) { ...o, a: 'wrong type?' } ->a : Symbol(a, Decl(objectSpread.ts, 55, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 57, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 56, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 56, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 56, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 58, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 58, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 58, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 57, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 59, 5)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 58, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 58, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 58, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 60, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 60, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 60, 32)) { ...o, ...swap }; // optional let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 62, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 62, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 64, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 64, 22)) let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 63, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 65, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 64, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 66, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 66, 21)) let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 65, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 67, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 67, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 66, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 66, 25)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 68, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 68, 25)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 67, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 67, 30)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 69, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 69, 30)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 68, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 68, 18)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 70, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 70, 18)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 71, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 71, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 71, 31)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 73, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 73, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 73, 31)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 72, 5)) ->b : Symbol(b, Decl(objectSpread.ts, 72, 38)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 74, 5)) +>b : Symbol(b, Decl(objectSpread.ts, 74, 38)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 73, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 73, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 73, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 73, 43)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 75, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 75, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 75, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 75, 43)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 74, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 74, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 76, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 76, 34)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 75, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 75, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 75, 31)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 77, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 77, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 77, 31)) { ...o, b: 'yeah', ['at the end']: 14 } ->b : Symbol(b, Decl(objectSpread.ts, 76, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 76, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 78, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 78, 22)) // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 78, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 80, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 79, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 79, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 79, 29)) ->a : Symbol(a, Decl(objectSpread.ts, 79, 51)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 81, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 81, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 81, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 81, 51)) // generics function f(t: T, u: U): { id: string, ...T, ...U } { ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->T : Symbol(T, Decl(objectSpread.ts, 82, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 82, 13)) ->t : Symbol(t, Decl(objectSpread.ts, 82, 17)) ->T : Symbol(T, Decl(objectSpread.ts, 82, 11)) ->u : Symbol(u, Decl(objectSpread.ts, 82, 22)) ->U : Symbol(U, Decl(objectSpread.ts, 82, 13)) ->id : Symbol(id, Decl(objectSpread.ts, 82, 31)) ->T : Symbol(T, Decl(objectSpread.ts, 82, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 82, 13)) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>T : Symbol(T, Decl(objectSpread.ts, 84, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 84, 13)) +>t : Symbol(t, Decl(objectSpread.ts, 84, 17)) +>T : Symbol(T, Decl(objectSpread.ts, 84, 11)) +>u : Symbol(u, Decl(objectSpread.ts, 84, 22)) +>U : Symbol(U, Decl(objectSpread.ts, 84, 13)) +>id : Symbol(id, Decl(objectSpread.ts, 84, 31)) +>T : Symbol(T, Decl(objectSpread.ts, 84, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 84, 13)) return { id: 'id', ...t, ...u }; ->id : Symbol(id, Decl(objectSpread.ts, 83, 12)) +>id : Symbol(id, Decl(objectSpread.ts, 85, 12)) } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : Symbol(exclusive, Decl(objectSpread.ts, 85, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 85, 16)) ->a : Symbol(a, Decl(objectSpread.ts, 85, 28)) ->b : Symbol(b, Decl(objectSpread.ts, 85, 39)) ->c : Symbol(c, Decl(objectSpread.ts, 85, 50)) ->d : Symbol(d, Decl(objectSpread.ts, 85, 61)) +>exclusive : Symbol(exclusive, Decl(objectSpread.ts, 87, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 87, 16)) +>a : Symbol(a, Decl(objectSpread.ts, 87, 28)) +>b : Symbol(b, Decl(objectSpread.ts, 87, 39)) +>c : Symbol(c, Decl(objectSpread.ts, 87, 50)) +>d : Symbol(d, Decl(objectSpread.ts, 87, 61)) f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 86, 7)) ->b : Symbol(b, Decl(objectSpread.ts, 86, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 86, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 86, 36)) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 88, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 88, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 88, 36)) let overlap: { id: string, a: number, b: string } = ->overlap : Symbol(overlap, Decl(objectSpread.ts, 87, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 87, 14)) ->a : Symbol(a, Decl(objectSpread.ts, 87, 26)) ->b : Symbol(b, Decl(objectSpread.ts, 87, 37)) +>overlap : Symbol(overlap, Decl(objectSpread.ts, 89, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 89, 14)) +>a : Symbol(a, Decl(objectSpread.ts, 89, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 89, 37)) f({ a: 1 }, { a: 2, b: 'extra' }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 17)) ->b : Symbol(b, Decl(objectSpread.ts, 88, 23)) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 90, 23)) let overlapConflict: { id:string, a: string } = ->overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 89, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 89, 22)) ->a : Symbol(a, Decl(objectSpread.ts, 89, 33)) +>overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 91, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 91, 22)) +>a : Symbol(a, Decl(objectSpread.ts, 91, 33)) f({ a: 1 }, { a: 'mismatch' }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 17)) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 92, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 92, 17)) let overwriteId: { id: boolean, a: number, c: number, d: string } = ->overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 91, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 91, 18)) ->a : Symbol(a, Decl(objectSpread.ts, 91, 31)) ->c : Symbol(c, Decl(objectSpread.ts, 91, 42)) ->d : Symbol(d, Decl(objectSpread.ts, 91, 53)) +>overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 93, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 93, 18)) +>a : Symbol(a, Decl(objectSpread.ts, 93, 31)) +>c : Symbol(c, Decl(objectSpread.ts, 93, 42)) +>d : Symbol(d, Decl(objectSpread.ts, 93, 53)) f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 92, 7)) ->id : Symbol(id, Decl(objectSpread.ts, 92, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 92, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 92, 33)) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 94, 7)) +>id : Symbol(id, Decl(objectSpread.ts, 94, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 94, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 94, 33)) class D { m() { }; q = 2; } ->D : Symbol(D, Decl(objectSpread.ts, 92, 44)) ->m : Symbol(D.m, Decl(objectSpread.ts, 94, 9)) ->q : Symbol(D.q, Decl(objectSpread.ts, 94, 18)) +>D : Symbol(D, Decl(objectSpread.ts, 94, 44)) +>m : Symbol(D.m, Decl(objectSpread.ts, 96, 9)) +>q : Symbol(D.q, Decl(objectSpread.ts, 96, 18)) let classesAreWrong: { id: string, ...C, ...D } = ->classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 95, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 95, 22)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 42)) ->D : Symbol(D, Decl(objectSpread.ts, 92, 44)) +>classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 97, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 97, 22)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 29)) +>D : Symbol(D, Decl(objectSpread.ts, 94, 44)) f(new C(), new D()) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 42)) ->D : Symbol(D, Decl(objectSpread.ts, 92, 44)) +>f : Symbol(f, Decl(objectSpread.ts, 81, 55)) +>C : Symbol(C, Decl(objectSpread.ts, 44, 29)) +>D : Symbol(D, Decl(objectSpread.ts, 94, 44)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 2b13af1d3d6e7..efab098fd6e22 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -223,7 +223,7 @@ getter.a = 12; >a : number >12 : 12 -// null, undefined, functions and primitives result in { } +// null, undefined, functions and primitives besides string result in { } let spreadNull = { ...null }; >spreadNull : {} >{ ...null } : {} @@ -238,10 +238,6 @@ let spreadNum = { ...12 }; >spreadNum : {} >{ ...12 } : {} -let spreadStr = { ...'foo' }; ->spreadStr : {} ->{ ...'foo' } : {} - let spreadBool = { ...false }; >spreadBool : {} >{ ...false } : {} @@ -253,6 +249,11 @@ let spreadFunc = { ...(function () { }) }; >(function () { }) : () => void >function () { } : () => void +// strings get a numeric indexer: [n: number]: string +let spreadStr = { ...'foo' }; +>spreadStr : { [x: number]: string; } +>{ ...'foo' } : { [x: number]: string; } + // methods are not enumerable class C { p = 1; m() { } } >C : C diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 84fb1cc4a76c1..b79354c4a9487 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -11,8 +11,8 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(30,12): error TS233 tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,17): error TS2339: Property 'undefined' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,11): error TS2339: Property 'toFixed' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,11): error TS2339: Property 'toFixed' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,11): error TS2339: Property 'length' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS2339: Property 'charAt' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,11): error TS2339: Property 'length' does not exist on type '{ [x: number]: string; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS2339: Property 'charAt' does not exist on type '{ [x: number]: string; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(55,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. @@ -86,10 +86,10 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(63,12): error TS232 let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' ~~~~~~ -!!! error TS2339: Property 'length' does not exist on type '{}'. +!!! error TS2339: Property 'length' does not exist on type '{ [x: number]: string; }'. spreadStr.charAt(1); // error, no methods either ~~~~~~ -!!! error TS2339: Property 'charAt' does not exist on type '{}'. +!!! error TS2339: Property 'charAt' does not exist on type '{ [x: number]: string; }'. let spreadBool = { ...true }; spreadBool.valueOf(); // error, what were you thinking? let spreadFunc = { ...function () { } } diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index 9dd9a8d41a1bf..46782aaa1d69d 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -1,4 +1,4 @@ -lib.d.ts(28,18): error TS2300: Duplicate identifier 'eval'. +lib.d.ts(32,18): error TS2300: Duplicate identifier 'eval'. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS1100: Invalid use of 'eval' in strict mode. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Duplicate identifier 'eval'. diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index e94775649e701..fc076e79543de 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -35,14 +35,16 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null, undefined, functions and primitives result in { } +// null, undefined, functions and primitives besides string result in { } let spreadNull = { ...null }; let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; -let spreadStr = { ...'foo' }; let spreadBool = { ...false }; let spreadFunc = { ...(function () { }) }; +// strings get a numeric indexer: [n: number]: string +let spreadStr = { ...'foo' }; + // methods are not enumerable class C { p = 1; m() { } } let c: C = new C() From ab1b2bb2a94ee6a44d4d3e343d5077b39bbb2d98 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 09:20:12 -0700 Subject: [PATCH 32/85] Reset baseline line number to the locally incorrect value --- .../reference/variableDeclarationInStrictMode1.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index 46782aaa1d69d..c47ac71f74869 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -1,4 +1,4 @@ -lib.d.ts(32,18): error TS2300: Duplicate identifier 'eval'. +lib.d.ts(28,18): error TS2300: Duplicate identifier 'eval'. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS1100: Invalid use of 'eval' in strict mode. tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Duplicate identifier 'eval'. @@ -9,4 +9,4 @@ tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Dup ~~~~ !!! error TS1100: Invalid use of 'eval' in strict mode. ~~~~ -!!! error TS2300: Duplicate identifier 'eval'. \ No newline at end of file +!!! error TS2300: Duplicate identifier 'eval'. From 3a85312dd816de4031fa1aae1ccccb53eca67e46 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 10:11:33 -0700 Subject: [PATCH 33/85] Remove trailing newline from baseline again --- .../reference/variableDeclarationInStrictMode1.errors.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt index c47ac71f74869..9dd9a8d41a1bf 100644 --- a/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt +++ b/tests/baselines/reference/variableDeclarationInStrictMode1.errors.txt @@ -9,4 +9,4 @@ tests/cases/compiler/variableDeclarationInStrictMode1.ts(2,5): error TS2300: Dup ~~~~ !!! error TS1100: Invalid use of 'eval' in strict mode. ~~~~ -!!! error TS2300: Duplicate identifier 'eval'. +!!! error TS2300: Duplicate identifier 'eval'. \ No newline at end of file From dceebcdc47d8f3cec9c05735a3df6f5882fb9743 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 11:36:40 -0700 Subject: [PATCH 34/85] Refactor getTypeFromTypeLiteral, from PR comments --- src/compiler/checker.ts | 110 ++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bfd6d78e89164..13de95485c8ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5710,67 +5710,69 @@ namespace ts { function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - const isSpread = (node.kind === SyntaxKind.TypeLiteral && - find((node as TypeLiteralNode).members, elt => elt.kind === SyntaxKind.SpreadTypeElement)); - let type: ObjectType; - if (isSpread) { - let members: Map; - let stringIndexInfo: IndexInfo; - let numberIndexInfo: IndexInfo; - const spreads: Type[] = []; - for (const member of (node as TypeLiteralNode).members) { - if (member.kind === SyntaxKind.SpreadTypeElement) { - if (members) { - spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); - members = undefined; - stringIndexInfo = undefined; - numberIndexInfo = undefined; - } - spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type)); - } - else if (member.kind === SyntaxKind.IndexSignature) { - const index = member as IndexSignatureDeclaration; - if (index.parameters.length === 1) { - const parameter = index.parameters[0]; - if (parameter && parameter.type) { - const indexInfo = createIndexInfo(index.type ? getTypeFromTypeNode(index.type) : anyType, - (getModifierFlags(index) & ModifierFlags.Readonly) !== 0, index); - if (parameter.type.kind === SyntaxKind.StringKeyword) { - stringIndexInfo = indexInfo; - } - else { - numberIndexInfo = indexInfo; - } - } + const hasSpread = (node.kind === SyntaxKind.TypeLiteral && + find((node as TypeLiteralNode).members, elt => elt.kind === SyntaxKind.SpreadTypeElement)); + if (hasSpread) { + return getTypeFromSpreadTypeLiteral(node, aliasSymbol, aliasTypeArguments); + } + + let type = createObjectType(TypeFlags.Anonymous, node.symbol); + type.aliasSymbol = aliasSymbol; + type.aliasTypeArguments = aliasTypeArguments; + links.resolvedType = type; + } + return links.resolvedType; + } + + function getTypeFromSpreadTypeLiteral(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + let members: Map; + let stringIndexInfo: IndexInfo; + let numberIndexInfo: IndexInfo; + const spreads: Type[] = []; + for (const member of (node as TypeLiteralNode).members) { + if (member.kind === SyntaxKind.SpreadTypeElement) { + if (members) { + spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); + members = undefined; + stringIndexInfo = undefined; + numberIndexInfo = undefined; + } + spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type)); + } + else if (member.kind === SyntaxKind.IndexSignature) { + const index = member as IndexSignatureDeclaration; + if (index.parameters.length === 1) { + const parameter = index.parameters[0]; + if (parameter && parameter.type) { + const indexInfo = createIndexInfo(index.type ? getTypeFromTypeNode(index.type) : anyType, + (getModifierFlags(index) & ModifierFlags.Readonly) !== 0, index); + if (parameter.type.kind === SyntaxKind.StringKeyword) { + stringIndexInfo = indexInfo; } - } - else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) { - // note that spread types don't include call and construct signatures - const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); - const text = getTextOfPropertyName(member.name); - const symbol = createSymbol(flags, text); - symbol.declarations = [member]; - symbol.valueDeclaration = member; - symbol.type = getTypeFromTypeNodeNoAlias((member as IndexSignatureDeclaration | PropertySignature | MethodSignature).type); - if (!members) { - members = createMap(); + else { + numberIndexInfo = indexInfo; } - members[symbol.name] = symbol; } } - if (members || stringIndexInfo || numberIndexInfo) { - spreads.push(createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); - } - return getSpreadType(spreads, node.symbol, aliasSymbol, aliasTypeArguments); } - else { - type = createObjectType(TypeFlags.Anonymous, node.symbol); + else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) { + // note that spread types don't include call and construct signatures + const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); + const text = getTextOfPropertyName(member.name); + const symbol = createSymbol(flags, text); + symbol.declarations = [member]; + symbol.valueDeclaration = member; + symbol.type = getTypeFromTypeNodeNoAlias((member as IndexSignatureDeclaration | PropertySignature | MethodSignature).type); + if (!members) { + members = createMap(); + } + members[symbol.name] = symbol; } - type.aliasSymbol = aliasSymbol; - type.aliasTypeArguments = aliasTypeArguments; - links.resolvedType = type; } - return links.resolvedType; + if (members || stringIndexInfo || numberIndexInfo) { + spreads.push(createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); + } + return getSpreadType(spreads, node.symbol, aliasSymbol, aliasTypeArguments); } function getSpreadType(types: Type[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { From ce84cee0f26192eed2aac3c405b06514fd7485a1 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 12 Oct 2016 11:53:54 -0700 Subject: [PATCH 35/85] Fix lint --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 13de95485c8ce..9a30fe435ae13 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5716,7 +5716,7 @@ namespace ts { return getTypeFromSpreadTypeLiteral(node, aliasSymbol, aliasTypeArguments); } - let type = createObjectType(TypeFlags.Anonymous, node.symbol); + const type = createObjectType(TypeFlags.Anonymous, node.symbol); type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; links.resolvedType = type; From 18c692a429421d7231d8a58b784c452e40176d82 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 19 Oct 2016 13:14:06 -0700 Subject: [PATCH 36/85] Remove type inference for spread types --- src/compiler/checker.ts | 88 +++++++++++------------------------------ 1 file changed, 23 insertions(+), 65 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 55d4361dc3e66..8e196da87de29 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8045,8 +8045,7 @@ namespace ts { return !!(type.flags & TypeFlags.TypeParameter || type.flags & TypeFlags.Reference && forEach((type).typeArguments, couldContainTypeParameters) || type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || - type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type) || - type.flags & TypeFlags.Spread && couldSpreadContainTypeParameters(type as SpreadType)); + type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(type)); } function couldUnionOrIntersectionContainTypeParameters(type: UnionOrIntersectionType): boolean { @@ -8056,11 +8055,6 @@ namespace ts { return type.couldContainTypeParameters; } - function couldSpreadContainTypeParameters(type: SpreadType): boolean { - return !!(type.right.flags & TypeFlags.TypeParameter || - type.left.flags & TypeFlags.Spread && (type.left as SpreadType).right.flags & TypeFlags.TypeParameter); - } - function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean { return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((type).types, t => isTypeParameterAtTopLevel(t, typeParameter)); } @@ -8124,16 +8118,6 @@ namespace ts { target = removeTypesFromUnionOrIntersection(target, matchingTypes); } } - if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { - // only the last type parameter is a valid inference site, - // and only if not followed by object literal properties. - if ((source as SpreadType).right.flags & TypeFlags.TypeParameter && - (target as SpreadType).right.flags & TypeFlags.TypeParameter) { - inferFromTypes((source as SpreadType).right, (target as SpreadType).right); - } - - return; - } if (target.flags & TypeFlags.TypeParameter) { // If target is a type parameter, make an inference, unless the source type contains // the anyFunctionType (the wildcard type that's used to avoid contextually typing functions). @@ -8210,57 +8194,31 @@ namespace ts { else { source = getApparentType(source); if (source.flags & TypeFlags.ObjectType) { - if (target.flags & TypeFlags.Spread) { - // with an object type as source, a spread target infers to its last type parameter it - // contains, after removing any properties from a object type that precedes the type parameter - // Note that the call to `typeDifference` creates a new anonymous type. - const spread = target as SpreadType; - const parameter = spread.right.flags & TypeFlags.TypeParameter ? spread.right : (spread.left as SpreadType).right; - const object = spread.right.flags & TypeFlags.TypeParameter ? emptyObjectType : spread.right as ResolvedType; - inferFromTypes(getTypeDifference(source, object), parameter); - target = object; + if (isInProcess(source, target)) { + return; } - inferFromStructure(source, target); - } - } - } - - function inferFromStructure(source: Type, target: Type) { - if (isInProcess(source, target)) { - return; - } - if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { - return; - } - const key = source.id + "," + target.id; - if (visited[key]) { - return; - } - visited[key] = true; - if (depth === 0) { - sourceStack = []; - targetStack = []; - } - sourceStack[depth] = source; - targetStack[depth] = target; - depth++; - inferFromProperties(source, target); - inferFromSignatures(source, target, SignatureKind.Call); - inferFromSignatures(source, target, SignatureKind.Construct); - inferFromIndexTypes(source, target); - depth--; - } - - function getTypeDifference(type: ObjectType, diff: ResolvedType): ResolvedType { - const members = createMap(); - for (const prop of getPropertiesOfObjectType(type)) { - if (!(prop.name in diff.members)) { - members[prop.name] = prop; + if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { + return; + } + const key = source.id + "," + target.id; + if (visited[key]) { + return; + } + visited[key] = true; + if (depth === 0) { + sourceStack = []; + targetStack = []; + } + sourceStack[depth] = source; + targetStack[depth] = target; + depth++; + inferFromProperties(source, target); + inferFromSignatures(source, target, SignatureKind.Call); + inferFromSignatures(source, target, SignatureKind.Construct); + inferFromIndexTypes(source, target); + depth--; } } - const stringIndexInfo = getIndexInfoOfType(diff, IndexKind.String) ? undefined : getIndexInfoOfType(type, IndexKind.String); - const numberIndexInfo = getIndexInfoOfType(diff, IndexKind.Number) ? undefined : getIndexInfoOfType(type, IndexKind.Number); - return createAnonymousType(type.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } function inferFromProperties(source: Type, target: Type) { From 62c186872d986dabf770dc7877de0f1167537af0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 19 Oct 2016 13:14:20 -0700 Subject: [PATCH 37/85] Update inference test for spread types --- .../reference/objectSpreadInference.js | 80 +------- .../reference/objectSpreadInference.symbols | 147 +-------------- .../reference/objectSpreadInference.types | 178 +----------------- .../types/spread/objectSpreadInference.ts | 46 +---- 4 files changed, 19 insertions(+), 432 deletions(-) diff --git a/tests/baselines/reference/objectSpreadInference.js b/tests/baselines/reference/objectSpreadInference.js index 06b17cfa1f948..77930e565118e 100644 --- a/tests/baselines/reference/objectSpreadInference.js +++ b/tests/baselines/reference/objectSpreadInference.js @@ -12,52 +12,12 @@ function generic(w: W, x: X, y: Y) { } let b: { b: number }; let c: { c: number }; -// should infer { t: {}, u: { b: number, c: number }, v: number } +// can only infer { t: {}, u: {}, v: {} } let i1 = infer({ ...b, ...c, a: 12 }); -// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i2 = infer2({ ...b, ...c, a: 12 }); -// should infer { t: {}, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i3 = generic(b, c, { a: 12 }); - -interface Preserved { - kind: 0 | 1 | 2 | 3; -} -class C implements Preserved { - kind: 0 = 0; - a = 1; - method() { return "C"; } -} -declare function revive(t: { ...T }): T; -function genericRevive(u: U) { - let us: { ...U }; - return revive(us); -} -// result should not have `method` -let result = revive({ a: 12, kind: 0 }); -// result2 should be of type C and have `method` -let result2 = revive({ a: 12, kind: 0 }); - -declare function destructureRevive(t: { ...T, a: number }): T; -function genericDestructureRevive(u: U) { - let us: { ...U }; - return destructureRevive(us); -} -// result3 is just `Preserved` because `a` and `method` both get removed -let result3 = destructureRevive({ a: 12, kind: 0 }); -// result4 is still C -- a is not removed -- because we specified the argument explicitly -let result4 = destructureRevive({ a: 12, kind: 0 }); -result4.method(); -result4.a; - -declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; -interface I { - a: number; - b: number; - [s: string]: number; - [n: number]: number; -} -let i: I; -let result5 = removeIndexSignature(i); //// [objectSpreadInference.js] @@ -75,37 +35,9 @@ function generic(w, x, y) { } var b; var c; -// should infer { t: {}, u: { b: number, c: number }, v: number } +// can only infer { t: {}, u: {}, v: {} } var i1 = infer(__assign({}, b, c, { a: 12 })); -// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } var i2 = infer2(__assign({}, b, c, { a: 12 })); -// should infer { t: {}, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } var i3 = generic(b, c, { a: 12 }); -var C = (function () { - function C() { - this.kind = 0; - this.a = 1; - } - C.prototype.method = function () { return "C"; }; - return C; -}()); -function genericRevive(u) { - var us; - return revive(us); -} -// result should not have `method` -var result = revive({ a: 12, kind: 0 }); -// result2 should be of type C and have `method` -var result2 = revive({ a: 12, kind: 0 }); -function genericDestructureRevive(u) { - var us; - return destructureRevive(us); -} -// result3 is just `Preserved` because `a` and `method` both get removed -var result3 = destructureRevive({ a: 12, kind: 0 }); -// result4 is still C -- a is not removed -- because we specified the argument explicitly -var result4 = destructureRevive({ a: 12, kind: 0 }); -result4.method(); -result4.a; -var i; -var result5 = removeIndexSignature(i); diff --git a/tests/baselines/reference/objectSpreadInference.symbols b/tests/baselines/reference/objectSpreadInference.symbols index f03cd6b44e11a..ddecc4d7e5d3f 100644 --- a/tests/baselines/reference/objectSpreadInference.symbols +++ b/tests/baselines/reference/objectSpreadInference.symbols @@ -78,19 +78,19 @@ let c: { c: number }; >c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) >c : Symbol(c, Decl(objectSpreadInference.ts, 12, 8)) -// should infer { t: {}, u: { b: number, c: number }, v: number } +// can only infer { t: {}, u: {}, v: {} } let i1 = infer({ ...b, ...c, a: 12 }); >i1 : Symbol(i1, Decl(objectSpreadInference.ts, 14, 3)) >infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1)) >a : Symbol(a, Decl(objectSpreadInference.ts, 14, 28)) -// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i2 = infer2({ ...b, ...c, a: 12 }); >i2 : Symbol(i2, Decl(objectSpreadInference.ts, 16, 3)) >infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79)) >a : Symbol(a, Decl(objectSpreadInference.ts, 16, 29)) -// should infer { t: {}, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i3 = generic(b, c, { a: 12 }); >i3 : Symbol(i3, Decl(objectSpreadInference.ts, 18, 3)) >generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80)) @@ -98,144 +98,3 @@ let i3 = generic(b, c, { a: 12 }); >c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3)) >a : Symbol(a, Decl(objectSpreadInference.ts, 18, 24)) -interface Preserved { ->Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) - - kind: 0 | 1 | 2 | 3; ->kind : Symbol(Preserved.kind, Decl(objectSpreadInference.ts, 20, 21)) -} -class C implements Preserved { ->C : Symbol(C, Decl(objectSpreadInference.ts, 22, 1)) ->Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) - - kind: 0 = 0; ->kind : Symbol(C.kind, Decl(objectSpreadInference.ts, 23, 30)) - - a = 1; ->a : Symbol(C.a, Decl(objectSpreadInference.ts, 24, 16)) - - method() { return "C"; } ->method : Symbol(C.method, Decl(objectSpreadInference.ts, 25, 10)) -} -declare function revive(t: { ...T }): T; ->revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 28, 24)) ->Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) ->t : Symbol(t, Decl(objectSpreadInference.ts, 28, 45)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 28, 24)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 28, 24)) - -function genericRevive(u: U) { ->genericRevive : Symbol(genericRevive, Decl(objectSpreadInference.ts, 28, 61)) ->U : Symbol(U, Decl(objectSpreadInference.ts, 29, 23)) ->Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) ->u : Symbol(u, Decl(objectSpreadInference.ts, 29, 44)) ->U : Symbol(U, Decl(objectSpreadInference.ts, 29, 23)) - - let us: { ...U }; ->us : Symbol(us, Decl(objectSpreadInference.ts, 30, 7)) ->U : Symbol(U, Decl(objectSpreadInference.ts, 29, 23)) - - return revive(us); ->revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) ->us : Symbol(us, Decl(objectSpreadInference.ts, 30, 7)) -} -// result should not have `method` -let result = revive({ a: 12, kind: 0 }); ->result : Symbol(result, Decl(objectSpreadInference.ts, 34, 3)) ->revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 34, 21)) ->kind : Symbol(kind, Decl(objectSpreadInference.ts, 34, 28)) - -// result2 should be of type C and have `method` -let result2 = revive({ a: 12, kind: 0 }); ->result2 : Symbol(result2, Decl(objectSpreadInference.ts, 36, 3)) ->revive : Symbol(revive, Decl(objectSpreadInference.ts, 27, 1)) ->C : Symbol(C, Decl(objectSpreadInference.ts, 22, 1)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 36, 25)) ->kind : Symbol(kind, Decl(objectSpreadInference.ts, 36, 32)) - -declare function destructureRevive(t: { ...T, a: number }): T; ->destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 38, 35)) ->Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) ->t : Symbol(t, Decl(objectSpreadInference.ts, 38, 56)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 38, 35)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 38, 66)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 38, 35)) - -function genericDestructureRevive(u: U) { ->genericDestructureRevive : Symbol(genericDestructureRevive, Decl(objectSpreadInference.ts, 38, 83)) ->U : Symbol(U, Decl(objectSpreadInference.ts, 39, 34)) ->Preserved : Symbol(Preserved, Decl(objectSpreadInference.ts, 18, 34)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 39, 57)) ->u : Symbol(u, Decl(objectSpreadInference.ts, 39, 71)) ->U : Symbol(U, Decl(objectSpreadInference.ts, 39, 34)) - - let us: { ...U }; ->us : Symbol(us, Decl(objectSpreadInference.ts, 40, 7)) ->U : Symbol(U, Decl(objectSpreadInference.ts, 39, 34)) - - return destructureRevive(us); ->destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) ->us : Symbol(us, Decl(objectSpreadInference.ts, 40, 7)) -} -// result3 is just `Preserved` because `a` and `method` both get removed -let result3 = destructureRevive({ a: 12, kind: 0 }); ->result3 : Symbol(result3, Decl(objectSpreadInference.ts, 44, 3)) ->destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 44, 33)) ->kind : Symbol(kind, Decl(objectSpreadInference.ts, 44, 40)) - -// result4 is still C -- a is not removed -- because we specified the argument explicitly -let result4 = destructureRevive({ a: 12, kind: 0 }); ->result4 : Symbol(result4, Decl(objectSpreadInference.ts, 46, 3)) ->destructureRevive : Symbol(destructureRevive, Decl(objectSpreadInference.ts, 36, 44)) ->C : Symbol(C, Decl(objectSpreadInference.ts, 22, 1)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 46, 36)) ->kind : Symbol(kind, Decl(objectSpreadInference.ts, 46, 43)) - -result4.method(); ->result4.method : Symbol(C.method, Decl(objectSpreadInference.ts, 25, 10)) ->result4 : Symbol(result4, Decl(objectSpreadInference.ts, 46, 3)) ->method : Symbol(C.method, Decl(objectSpreadInference.ts, 25, 10)) - -result4.a; ->result4.a : Symbol(C.a, Decl(objectSpreadInference.ts, 24, 16)) ->result4 : Symbol(result4, Decl(objectSpreadInference.ts, 46, 3)) ->a : Symbol(C.a, Decl(objectSpreadInference.ts, 24, 16)) - -declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; ->removeIndexSignature : Symbol(removeIndexSignature, Decl(objectSpreadInference.ts, 48, 10)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 50, 38)) ->t : Symbol(t, Decl(objectSpreadInference.ts, 50, 41)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 50, 38)) ->a : Symbol(a, Decl(objectSpreadInference.ts, 50, 51)) ->s : Symbol(s, Decl(objectSpreadInference.ts, 50, 64)) ->n : Symbol(n, Decl(objectSpreadInference.ts, 50, 85)) ->T : Symbol(T, Decl(objectSpreadInference.ts, 50, 38)) - -interface I { ->I : Symbol(I, Decl(objectSpreadInference.ts, 50, 110)) - - a: number; ->a : Symbol(I.a, Decl(objectSpreadInference.ts, 51, 13)) - - b: number; ->b : Symbol(I.b, Decl(objectSpreadInference.ts, 52, 14)) - - [s: string]: number; ->s : Symbol(s, Decl(objectSpreadInference.ts, 54, 5)) - - [n: number]: number; ->n : Symbol(n, Decl(objectSpreadInference.ts, 55, 5)) -} -let i: I; ->i : Symbol(i, Decl(objectSpreadInference.ts, 57, 3)) ->I : Symbol(I, Decl(objectSpreadInference.ts, 50, 110)) - -let result5 = removeIndexSignature(i); ->result5 : Symbol(result5, Decl(objectSpreadInference.ts, 58, 3)) ->removeIndexSignature : Symbol(removeIndexSignature, Decl(objectSpreadInference.ts, 48, 10)) ->i : Symbol(i, Decl(objectSpreadInference.ts, 57, 3)) - diff --git a/tests/baselines/reference/objectSpreadInference.types b/tests/baselines/reference/objectSpreadInference.types index 55303119932e1..3e71e29b83c48 100644 --- a/tests/baselines/reference/objectSpreadInference.types +++ b/tests/baselines/reference/objectSpreadInference.types @@ -83,10 +83,10 @@ let c: { c: number }; >c : { c: number; } >c : number -// should infer { t: {}, u: { b: number, c: number }, v: number } +// can only infer { t: {}, u: {}, v: {} } let i1 = infer({ ...b, ...c, a: 12 }); ->i1 : { t: {}; u: { c: number; b: number; }; v: number; } ->infer({ ...b, ...c, a: 12 }) : { t: {}; u: { c: number; b: number; }; v: number; } +>i1 : { t: {}; u: {}; v: {}; } +>infer({ ...b, ...c, a: 12 }) : { t: {}; u: {}; v: {}; } >infer : (tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; } >{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; } >b : any @@ -94,10 +94,10 @@ let i1 = infer({ ...b, ...c, a: 12 }); >a : number >12 : 12 -// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i2 = infer2({ ...b, ...c, a: 12 }); ->i2 : { t: { a: number; c: number; b: number; }; u: {}; v: {}; } ->infer2({ ...b, ...c, a: 12 }) : { t: { a: number; c: number; b: number; }; u: {}; v: {}; } +>i2 : { t: {}; u: {}; v: {}; } +>infer2({ ...b, ...c, a: 12 }) : { t: {}; u: {}; v: {}; } >infer2 : (utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; } >{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; } >b : any @@ -105,7 +105,7 @@ let i2 = infer2({ ...b, ...c, a: 12 }); >a : number >12 : 12 -// should infer { t: {}, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i3 = generic(b, c, { a: 12 }); >i3 : { t: {}; u: {}; v: {}; } >generic(b, c, { a: 12 }) : { t: {}; u: {}; v: {}; } @@ -116,167 +116,3 @@ let i3 = generic(b, c, { a: 12 }); >a : number >12 : 12 -interface Preserved { ->Preserved : Preserved - - kind: 0 | 1 | 2 | 3; ->kind : 0 | 1 | 2 | 3 -} -class C implements Preserved { ->C : C ->Preserved : Preserved - - kind: 0 = 0; ->kind : 0 ->0 : 0 - - a = 1; ->a : number ->1 : 1 - - method() { return "C"; } ->method : () => string ->"C" : "C" -} -declare function revive(t: { ...T }): T; ->revive : (t: { ...T }) => T ->T : T ->Preserved : Preserved ->t : { ...T } ->T : T ->T : T - -function genericRevive(u: U) { ->genericRevive : (u: U) => U ->U : U ->Preserved : Preserved ->u : U ->U : U - - let us: { ...U }; ->us : { ...U } ->U : U - - return revive(us); ->revive(us) : U ->revive : (t: { ...T }) => T ->us : { ...U } -} -// result should not have `method` -let result = revive({ a: 12, kind: 0 }); ->result : { a: number; kind: 0; } ->revive({ a: 12, kind: 0 }) : { a: number; kind: 0; } ->revive : (t: { ...T }) => T ->{ a: 12, kind: 0 } : { a: number; kind: 0; } ->a : number ->12 : 12 ->kind : number ->0 : 0 - -// result2 should be of type C and have `method` -let result2 = revive({ a: 12, kind: 0 }); ->result2 : C ->revive({ a: 12, kind: 0 }) : C ->revive : (t: { ...T }) => T ->C : C ->{ a: 12, kind: 0 } : { a: number; kind: 0; } ->a : number ->12 : 12 ->kind : number ->0 : 0 - -declare function destructureRevive(t: { ...T, a: number }): T; ->destructureRevive : (t: { ...T; a: number; }) => T ->T : T ->Preserved : Preserved ->t : { ...T; a: number; } ->T : T ->a : number ->T : T - -function genericDestructureRevive(u: U) { ->genericDestructureRevive : (u: U) => Preserved ->U : U ->Preserved : Preserved ->a : number ->u : U ->U : U - - let us: { ...U }; ->us : { ...U } ->U : U - - return destructureRevive(us); ->destructureRevive(us) : Preserved ->destructureRevive : (t: { ...T; a: number; }) => T ->us : { ...U } -} -// result3 is just `Preserved` because `a` and `method` both get removed -let result3 = destructureRevive({ a: 12, kind: 0 }); ->result3 : { kind: 0; } ->destructureRevive({ a: 12, kind: 0 }) : { kind: 0; } ->destructureRevive : (t: { ...T; a: number; }) => T ->{ a: 12, kind: 0 } : { a: number; kind: 0; } ->a : number ->12 : 12 ->kind : number ->0 : 0 - -// result4 is still C -- a is not removed -- because we specified the argument explicitly -let result4 = destructureRevive({ a: 12, kind: 0 }); ->result4 : C ->destructureRevive({ a: 12, kind: 0 }) : C ->destructureRevive : (t: { ...T; a: number; }) => T ->C : C ->{ a: 12, kind: 0 } : { a: number; kind: 0; } ->a : number ->12 : 12 ->kind : number ->0 : 0 - -result4.method(); ->result4.method() : string ->result4.method : () => string ->result4 : C ->method : () => string - -result4.a; ->result4.a : number ->result4 : C ->a : number - -declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; ->removeIndexSignature : (t: { ...T; [s: string]: number; [n: number]: number; a: number; }) => T ->T : T ->t : { ...T; [s: string]: number; [n: number]: number; a: number; } ->T : T ->a : number ->s : string ->n : number ->T : T - -interface I { ->I : I - - a: number; ->a : number - - b: number; ->b : number - - [s: string]: number; ->s : string - - [n: number]: number; ->n : number -} -let i: I; ->i : I ->I : I - -let result5 = removeIndexSignature(i); ->result5 : { b: number; } ->removeIndexSignature(i) : { b: number; } ->removeIndexSignature : (t: { ...T; [s: string]: number; [n: number]: number; a: number; }) => T ->i : I - diff --git a/tests/cases/conformance/types/spread/objectSpreadInference.ts b/tests/cases/conformance/types/spread/objectSpreadInference.ts index 1984193241988..9608f0a16cb95 100644 --- a/tests/cases/conformance/types/spread/objectSpreadInference.ts +++ b/tests/cases/conformance/types/spread/objectSpreadInference.ts @@ -11,49 +11,9 @@ function generic(w: W, x: X, y: Y) { } let b: { b: number }; let c: { c: number }; -// should infer { t: {}, u: { b: number, c: number }, v: number } +// can only infer { t: {}, u: {}, v: {} } let i1 = infer({ ...b, ...c, a: 12 }); -// should infer { t: { a: number, b: number, c: number }, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i2 = infer2({ ...b, ...c, a: 12 }); -// should infer { t: {}, u: {}, v: {} } +// can only infer { t: {}, u: {}, v: {} } let i3 = generic(b, c, { a: 12 }); - -interface Preserved { - kind: 0 | 1 | 2 | 3; -} -class C implements Preserved { - kind: 0 = 0; - a = 1; - method() { return "C"; } -} -declare function revive(t: { ...T }): T; -function genericRevive(u: U) { - let us: { ...U }; - return revive(us); -} -// result should not have `method` -let result = revive({ a: 12, kind: 0 }); -// result2 should be of type C and have `method` -let result2 = revive({ a: 12, kind: 0 }); - -declare function destructureRevive(t: { ...T, a: number }): T; -function genericDestructureRevive(u: U) { - let us: { ...U }; - return destructureRevive(us); -} -// result3 is just `Preserved` because `a` and `method` both get removed -let result3 = destructureRevive({ a: 12, kind: 0 }); -// result4 is still C -- a is not removed -- because we specified the argument explicitly -let result4 = destructureRevive({ a: 12, kind: 0 }); -result4.method(); -result4.a; - -declare function removeIndexSignature(t: { ...T, a: number, [s: string]: number, [n: number]: number }): T; -interface I { - a: number; - b: number; - [s: string]: number; - [n: number]: number; -} -let i: I; -let result5 = removeIndexSignature(i); From a90905358d5baf6224392bac9ba62394e102d07e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 19 Oct 2016 15:04:30 -0700 Subject: [PATCH 38/85] Make spread assignability and apparent type stricter Assignability now does not allow properties to the left of a type parameter. Apparent type now only returns the apparent type of the right-most spread member. --- src/compiler/checker.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8e196da87de29..e3651f6cf3014 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4515,7 +4515,7 @@ namespace ts { } function getApparentTypeOfSpread(type: SpreadType) { - return getSpreadType([getApparentType(type.left), getApparentType(type.right)], type.symbol); + return getApparentType(type.right); } /** @@ -5837,9 +5837,8 @@ namespace ts { left.flags & TypeFlags.Spread && (left as SpreadType).right.flags & TypeFlags.ObjectType) { // simplify two adjacent object types: T ... { x } ... { y } becomes T ... { x, y } - // Note: left.left is always a spread type. Can we use this fact to avoid calling getSpreadType again? - return getSpreadType([getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments), - (left as SpreadType).left], symbol, aliasSymbol, aliasTypeArguments); + const simplified = getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments); + return getSpreadType([(left as SpreadType).left, simplified], symbol, aliasSymbol, aliasTypeArguments); } if (left.flags & TypeFlags.Intersection) { const spreads = map((left as IntersectionType).types, @@ -6872,7 +6871,7 @@ namespace ts { if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { // you only see this for spreads with type parameters - if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType))) { + if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType, /*atRightEdge*/ true))) { if (reportErrors) { reportRelationError(headMessage, source, target); } @@ -6945,13 +6944,14 @@ namespace ts { return Ternary.False; } - function spreadTypeRelatedTo(source: SpreadType, target: SpreadType): boolean { + function spreadTypeRelatedTo(source: SpreadType, target: SpreadType, atRightEdge?: boolean): boolean { // If the right side of a spread type is ObjectType, then the left side must be a Spread. // Structural compatibility of the spreads' object types are checked separately in isRelatedTo, // so just skip them for now. if (source.right.flags & TypeFlags.ObjectType || target.right.flags & TypeFlags.ObjectType) { - return spreadTypeRelatedTo(source.right.flags & TypeFlags.ObjectType ? source.left as SpreadType : source, - target.right.flags & TypeFlags.ObjectType ? target.left as SpreadType : target); + return atRightEdge && + spreadTypeRelatedTo(source.right.flags & TypeFlags.ObjectType ? source.left as SpreadType : source, + target.right.flags & TypeFlags.ObjectType ? target.left as SpreadType : target); } // If both right sides are type parameters, then they must be identical for the spread types to be related. // It also means that the left sides are either spread types or object types. @@ -6964,9 +6964,9 @@ namespace ts { // If the left sides are both spread types, then recursively check them. return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); } - // If the left sides are both object types, then isRelatedTo will check the structural compatibility next. - // Otherwise, one side has more type parameters than the other and the spread types are not related. - return !!(source.left.flags & TypeFlags.ObjectType && target.left.flags & TypeFlags.ObjectType); + // If the left sides are both object types, then we should be at the end and both should be emptyObjectType. + // If not, we can't know what properties might have been overwritten, so fail. + return source.left === emptyObjectType && target.left === emptyObjectType; } function isIdenticalTo(source: Type, target: Type): Ternary { From ad10ec56c1214ee5a52f1de3f2dce00f0ca3d025 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 19 Oct 2016 15:05:42 -0700 Subject: [PATCH 39/85] Update tests w/spread assignability+apparent type --- tests/baselines/reference/objectSpread.js | 8 +- .../baselines/reference/objectSpread.symbols | 16 +-- tests/baselines/reference/objectSpread.types | 40 ++++---- .../reference/objectSpreadGeneric.errors.txt | 49 ++++++---- .../reference/objectSpreadGeneric.js | 36 ++++--- .../reference/objectSpreadIntersection.js | 32 +++--- .../objectSpreadIntersection.symbols | 70 ++++++------- .../reference/objectSpreadIntersection.types | 98 +++++++++---------- .../baselines/reference/objectSpreadUnion.js | 16 +-- .../reference/objectSpreadUnion.symbols | 34 +++---- .../reference/objectSpreadUnion.types | 48 ++++----- .../conformance/types/spread/objectSpread.ts | 6 +- .../types/spread/objectSpreadGeneric.ts | 18 ++-- .../types/spread/objectSpreadIntersection.ts | 24 ++--- .../types/spread/objectSpreadUnion.ts | 12 +-- 15 files changed, 262 insertions(+), 245 deletions(-) diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index efb73bcb35399..359284f9c6c51 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -83,8 +83,8 @@ let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // generics -function f(t: T, u: U): { id: string, ...T, ...U } { - return { id: 'id', ...t, ...u }; +function f(t: T, u: U): { ...T, ...U, id: string } { + return { ...t, ...u, id: 'id' }; } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = f({ a: 1, b: 'yes' }, { c: 'no', d: false }) @@ -92,7 +92,7 @@ let overlap: { id: string, a: number, b: string } = f({ a: 1 }, { a: 2, b: 'extra' }) let overlapConflict: { id:string, a: string } = f({ a: 1 }, { a: 'mismatch' }) -let overwriteId: { id: boolean, a: number, c: number, d: string } = +let overwriteId: { id: string, a: number, c: number, d: string } = f({ a: 1, id: true }, { c: 1, d: 'no' }) class D { m() { }; q = 2; } @@ -172,7 +172,7 @@ var a = 12; var shortCutted = __assign({}, o, { a: a }); // generics function f(t, u) { - return __assign({ id: 'id' }, t, u); + return __assign({}, t, u, { id: 'id' }); } var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false }); var overlap = f({ a: 1 }, { a: 2, b: 'extra' }); diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index d23016ddb1e15..fb7a1e22b33f3 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -290,7 +290,7 @@ let shortCutted: { a: number, b: string } = { ...o, a } >a : Symbol(a, Decl(objectSpread.ts, 81, 51)) // generics -function f(t: T, u: U): { id: string, ...T, ...U } { +function f(t: T, u: U): { ...T, ...U, id: string } { >f : Symbol(f, Decl(objectSpread.ts, 81, 55)) >T : Symbol(T, Decl(objectSpread.ts, 84, 11)) >U : Symbol(U, Decl(objectSpread.ts, 84, 13)) @@ -298,12 +298,12 @@ function f(t: T, u: U): { id: string, ...T, ...U } { >T : Symbol(T, Decl(objectSpread.ts, 84, 11)) >u : Symbol(u, Decl(objectSpread.ts, 84, 22)) >U : Symbol(U, Decl(objectSpread.ts, 84, 13)) ->id : Symbol(id, Decl(objectSpread.ts, 84, 31)) >T : Symbol(T, Decl(objectSpread.ts, 84, 11)) >U : Symbol(U, Decl(objectSpread.ts, 84, 13)) +>id : Symbol(id, Decl(objectSpread.ts, 84, 43)) - return { id: 'id', ...t, ...u }; ->id : Symbol(id, Decl(objectSpread.ts, 85, 12)) + return { ...t, ...u, id: 'id' }; +>id : Symbol(id, Decl(objectSpread.ts, 85, 24)) } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = >exclusive : Symbol(exclusive, Decl(objectSpread.ts, 87, 3)) @@ -342,12 +342,12 @@ let overlapConflict: { id:string, a: string } = >a : Symbol(a, Decl(objectSpread.ts, 92, 7)) >a : Symbol(a, Decl(objectSpread.ts, 92, 17)) -let overwriteId: { id: boolean, a: number, c: number, d: string } = +let overwriteId: { id: string, a: number, c: number, d: string } = >overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 93, 3)) >id : Symbol(id, Decl(objectSpread.ts, 93, 18)) ->a : Symbol(a, Decl(objectSpread.ts, 93, 31)) ->c : Symbol(c, Decl(objectSpread.ts, 93, 42)) ->d : Symbol(d, Decl(objectSpread.ts, 93, 53)) +>a : Symbol(a, Decl(objectSpread.ts, 93, 30)) +>c : Symbol(c, Decl(objectSpread.ts, 93, 41)) +>d : Symbol(d, Decl(objectSpread.ts, 93, 52)) f({ a: 1, id: true }, { c: 1, d: 'no' }) >f : Symbol(f, Decl(objectSpread.ts, 81, 55)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index efab098fd6e22..b6fcb9150bf3a 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -423,24 +423,24 @@ let shortCutted: { a: number, b: string } = { ...o, a } >a : number // generics -function f(t: T, u: U): { id: string, ...T, ...U } { ->f : (t: T, u: U) => { id: string; ...T; ...U } +function f(t: T, u: U): { ...T, ...U, id: string } { +>f : (t: T, u: U) => { ...T; ...U; id: string; } >T : T >U : U >t : T >T : T >u : U >U : U ->id : string >T : T >U : U - - return { id: 'id', ...t, ...u }; ->{ id: 'id', ...t, ...u } : { id: string; ...T; ...U } >id : string ->'id' : "id" + + return { ...t, ...u, id: 'id' }; +>{ ...t, ...u, id: 'id' } : { ...T; ...U; id: string; } >t : any >u : any +>id : string +>'id' : "id" } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = >exclusive : { id: string; a: number; b: string; c: string; d: boolean; } @@ -451,8 +451,8 @@ let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = >d : boolean f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { c: string; d: boolean; a: number; b: string; id: string; } ->f : (t: T, u: U) => { id: string; ...T; ...U } +>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { id: string; c: string; d: boolean; a: number; b: string; } +>f : (t: T, u: U) => { ...T; ...U; id: string; } >{ a: 1, b: 'yes' } : { a: number; b: string; } >a : number >1 : 1 @@ -471,8 +471,8 @@ let overlap: { id: string, a: number, b: string } = >b : string f({ a: 1 }, { a: 2, b: 'extra' }) ->f({ a: 1 }, { a: 2, b: 'extra' }) : { a: number; b: string; id: string; } ->f : (t: T, u: U) => { id: string; ...T; ...U } +>f({ a: 1 }, { a: 2, b: 'extra' }) : { id: string; a: number; b: string; } +>f : (t: T, u: U) => { ...T; ...U; id: string; } >{ a: 1 } : { a: number; } >a : number >1 : 1 @@ -488,8 +488,8 @@ let overlapConflict: { id:string, a: string } = >a : string f({ a: 1 }, { a: 'mismatch' }) ->f({ a: 1 }, { a: 'mismatch' }) : { a: string; id: string; } ->f : (t: T, u: U) => { id: string; ...T; ...U } +>f({ a: 1 }, { a: 'mismatch' }) : { id: string; a: string; } +>f : (t: T, u: U) => { ...T; ...U; id: string; } >{ a: 1 } : { a: number; } >a : number >1 : 1 @@ -497,16 +497,16 @@ let overlapConflict: { id:string, a: string } = >a : string >'mismatch' : "mismatch" -let overwriteId: { id: boolean, a: number, c: number, d: string } = ->overwriteId : { id: boolean; a: number; c: number; d: string; } ->id : boolean +let overwriteId: { id: string, a: number, c: number, d: string } = +>overwriteId : { id: string; a: number; c: number; d: string; } +>id : string >a : number >c : number >d : string f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f({ a: 1, id: true }, { c: 1, d: 'no' }) : { c: number; d: string; a: number; id: boolean; } ->f : (t: T, u: U) => { id: string; ...T; ...U } +>f({ a: 1, id: true }, { c: 1, d: 'no' }) : { id: string; c: number; d: string; a: number; } +>f : (t: T, u: U) => { ...T; ...U; id: string; } >{ a: 1, id: true } : { a: number; id: true; } >a : number >1 : 1 @@ -531,8 +531,8 @@ let classesAreWrong: { id: string, ...C, ...D } = >D : D f(new C(), new D()) ->f(new C(), new D()) : { q: number; p: number; id: string; } ->f : (t: T, u: U) => { id: string; ...T; ...U } +>f(new C(), new D()) : { id: string; q: number; p: number; } +>f : (t: T, u: U) => { ...T; ...U; id: string; } >new C() : C >C : typeof C >new D() : D diff --git a/tests/baselines/reference/objectSpreadGeneric.errors.txt b/tests/baselines/reference/objectSpreadGeneric.errors.txt index 6e55040f22391..8b9c767f6de3d 100644 --- a/tests/baselines/reference/objectSpreadGeneric.errors.txt +++ b/tests/baselines/reference/objectSpreadGeneric.errors.txt @@ -4,17 +4,19 @@ tests/cases/conformance/types/spread/objectSpreadGeneric.ts(11,11): error TS2322 tests/cases/conformance/types/spread/objectSpreadGeneric.ts(12,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. tests/cases/conformance/types/spread/objectSpreadGeneric.ts(13,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. tests/cases/conformance/types/spread/objectSpreadGeneric.ts(14,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(16,11): error TS2322: Type '{ first: string; ...T; ...U }' is not assignable to type '{ first: string; ...T; ...U }'. tests/cases/conformance/types/spread/objectSpreadGeneric.ts(19,11): error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(32,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(40,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - Property 'first' is missing in type '{ third: string; second: string; firrrrrrst: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(42,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - Property 'second' is missing in type '{ third: string; ssssssssecond: string; first: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - Property 'third' is missing in type '{ thirrrrrrrd: string; second: string; first: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(26,11): error TS2322: Type '{ sn?: boolean; ...T; sn?: string | number; }' is not assignable to type '{ ...T; sn?: string | number | boolean; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(32,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(34,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(36,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; second: string; secondsecond: string; third: string; ...T; ...U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(42,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(46,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (11 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (16 errors) ==== function f(t: T, u: U, v: V): void { let o: { ...T, ...U, ...V }; let uus: { ...U, ...U}; @@ -42,48 +44,57 @@ tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322 ~~~~~~~~ !!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok - const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // ok + const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // error, not assignable + ~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; ...U }' is not assignable to type '{ first: string; ...T; ...U }'. const emptyTarget: { } = { ...t, ...u } // ok const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) ~~~~~~~~~~~ !!! error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } let optionalNumber: { sn?: number }; let optionalString: { sn?: string }; let optionalBoolean: { sn?: boolean }; const unionCutoff: { ...T, sn?: number | string | boolean } = - { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } // ok + ~~~~~~~~~~~ +!!! error TS2322: Type '{ sn?: boolean; ...T; sn?: string | number; }' is not assignable to type '{ ...T; sn?: string | number | boolean; }'. + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } unionCutoff.sn; // ok const optionalCutoff = { ...t, ...optionalNumber }; // ok optionalCutoff.sn; // ok const interspersed: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // ok + ~~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable const interspersedMissingU: { first: string, second: string, ...T, third: string } = ~~~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }'. + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + ~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; second: string; secondsecond: string; third: string; ...T; ...U }'. + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = ~~~~~~~~~~~~~ !!! error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -!!! error TS2322: Property 'first' is missing in type '{ third: string; second: string; firrrrrrst: string; }'. - { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = ~~~~~~~~~~~~~~ !!! error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -!!! error TS2322: Property 'second' is missing in type '{ third: string; ssssssssecond: string; first: string; }'. - { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = ~~~~~~~~~~~~ !!! error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -!!! error TS2322: Property 'third' is missing in type '{ thirrrrrrrd: string; second: string; first: string; }'. - { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable } \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadGeneric.js b/tests/baselines/reference/objectSpreadGeneric.js index 9414b9ef76e86..fa19e47df39e7 100644 --- a/tests/baselines/reference/objectSpreadGeneric.js +++ b/tests/baselines/reference/objectSpreadGeneric.js @@ -14,36 +14,38 @@ function f(t: T, u: U, v: V): void { const missingU: { ...T, ...V } = o; // error, missing U const missingV: { ...T, ...U } = o; // error, missing V const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok - const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // ok + const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // error, not assignable const emptyTarget: { } = { ...t, ...u } // ok const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } let optionalNumber: { sn?: number }; let optionalString: { sn?: string }; let optionalBoolean: { sn?: boolean }; const unionCutoff: { ...T, sn?: number | string | boolean } = - { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } // ok + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } unionCutoff.sn; // ok const optionalCutoff = { ...t, ...optionalNumber }; // ok optionalCutoff.sn; // ok const interspersed: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // ok + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable const interspersedMissingU: { first: string, second: string, ...T, third: string } = { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = - { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable } @@ -71,21 +73,23 @@ function f(t, u, v) { var missingU = o; // error, missing U var missingV = o; // error, missing V var atEnd = __assign({}, t, u, { second: 'foo' }); // ok - var atBeginning = __assign({ first: 'foo' }, t, u); // ok + var atBeginning = __assign({ first: 'foo' }, t, u); // error, not assignable var emptyTarget = __assign({}, t, u); // ok var emptySource = {}; // error, {} is not assignable to U (or T) + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } var optionalNumber; var optionalString; var optionalBoolean; - var unionCutoff = __assign({}, optionalBoolean, t, optionalString, optionalNumber); // ok + var unionCutoff = __assign({}, optionalBoolean, t, optionalString, optionalNumber); unionCutoff.sn; // ok var optionalCutoff = __assign({}, t, optionalNumber); // ok optionalCutoff.sn; // ok - var interspersed = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // ok + var interspersed = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, not assignable var interspersedMissingU = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, 'U' is missing - var interspersedOrder1 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // ok - var interspersedOrder2 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // ok - var mismatchFirst = __assign({ firrrrrrst: '1' }, t, { second: '2' }, u, { third: '3' }); // error, 'first' not found - var mismatchSecond = __assign({ first: '1' }, t, { ssssssssecond: '2' }, u, { third: '3' }); // error, 'second' not found - var mismatchLast = __assign({ first: '1' }, t, { second: '2' }, u, { thirrrrrrrd: '3' }); // error, 'third' not found + var interspersedOrder1 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // error, not assignable + var interspersedOrder2 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // error, not assignable + var mismatchFirst = __assign({ firrrrrrst: '1' }, t, { second: '2' }, u, { third: '3' }); // error, not assignable + var mismatchSecond = __assign({ first: '1' }, t, { ssssssssecond: '2' }, u, { third: '3' }); // error, not assignable + var mismatchLast = __assign({ first: '1' }, t, { second: '2' }, u, { thirrrrrrrd: '3' }); // error, not assignable } diff --git a/tests/baselines/reference/objectSpreadIntersection.js b/tests/baselines/reference/objectSpreadIntersection.js index cb93c54796334..0a7f1ddfcee43 100644 --- a/tests/baselines/reference/objectSpreadIntersection.js +++ b/tests/baselines/reference/objectSpreadIntersection.js @@ -2,9 +2,9 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { let tu: T | U; let uv: U & V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); - let assignable: { id: string, ...(T | U), ...(U & V) } = result; + let result = { ...tu, ...uv, id: 'foo' }; + let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); + let assignable: { ...(T | U), ...(U & V), id: string } = result; } // concrete types work interface A1 { a: number } @@ -16,23 +16,23 @@ let assignable: { ...(A1 & A2) } = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; - let result = { id: 'foo', ...tuv }; - let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; - let assignable: { id: string, ...(T & U & V) } = result; + let result = { ...tuv, id: 'bar' }; + let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; + let assignable: { ...(T & U & V), id: string } = result; } function iteratedDoubleIntersection(t: T, u: U, v: V): void { let tu: T & U; let uv: U & V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; - let assignable: { id: string, ...(T & U), ...(U & V) } = result; + let result = { ...tu, ...uv, id: 'baz' }; + let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; + let assignable: { ...(T & U), ...(U & V), id: string } = result; } function iteratedIntersectionUnion(t: T, u: U, v: V): void { let tu: T & U; let uv: U | V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); - let assignable: { id: string, ...(T & U), ...(U | V) } = result; + let result = { ...tu, ...uv, id: 'qux' }; + let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); + let assignable: { ...(T & U), ...(U | V), id: string } = result; } @@ -49,7 +49,7 @@ var __assign = (this && this.__assign) || Object.assign || function(t) { function iteratedUnionIntersection(t, u, v) { var tu; var uv; - var result = __assign({ id: 'bar' }, tu, uv); + var result = __assign({}, tu, uv, { id: 'foo' }); var expected; var assignable = result; } @@ -59,21 +59,21 @@ var sn = result.a; var assignable = result; function tripleIntersection(t, u, v) { var tuv; - var result = __assign({ id: 'foo' }, tuv); + var result = __assign({}, tuv, { id: 'bar' }); var expected = result; var assignable = result; } function iteratedDoubleIntersection(t, u, v) { var tu; var uv; - var result = __assign({ id: 'bar' }, tu, uv); + var result = __assign({}, tu, uv, { id: 'baz' }); var expected; var assignable = result; } function iteratedIntersectionUnion(t, u, v) { var tu; var uv; - var result = __assign({ id: 'bar' }, tu, uv); + var result = __assign({}, tu, uv, { id: 'qux' }); var expected; var assignable = result; } diff --git a/tests/baselines/reference/objectSpreadIntersection.symbols b/tests/baselines/reference/objectSpreadIntersection.symbols index f45b04a20a51c..c59c37670b25d 100644 --- a/tests/baselines/reference/objectSpreadIntersection.symbols +++ b/tests/baselines/reference/objectSpreadIntersection.symbols @@ -21,31 +21,31 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) - let result = { id: 'bar', ...tu, ...uv }; + let result = { ...tu, ...uv, id: 'foo' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 3, 18)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 3, 32)) - let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); + let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); >expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 4, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 20)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 49)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 32)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 80)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 61)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 103)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 86)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 115)) - let assignable: { id: string, ...(T | U), ...(U & V) } = result; + let assignable: { ...(T | U), ...(U & V), id: string } = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 5, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 5, 21)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 5, 45)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) } // concrete types work @@ -95,26 +95,26 @@ function tripleIntersection(t: T, u: U, v: V): void { >U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) - let result = { id: 'foo', ...tuv }; + let result = { ...tuv, id: 'bar' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 17, 18)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 17, 26)) - let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; + let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; >expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 18, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 19)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 42)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 25)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 65)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 48)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 71)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) - let assignable: { id: string, ...(T & U & V) } = result; + let assignable: { ...(T & U & V), id: string } = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 19, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 19, 21)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 19, 37)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) } function iteratedDoubleIntersection(t: T, u: U, v: V): void { @@ -139,31 +139,31 @@ function iteratedDoubleIntersection(t: T, u: U, v: V): void { >U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) - let result = { id: 'bar', ...tu, ...uv }; + let result = { ...tu, ...uv, id: 'baz' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 24, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 24, 18)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 24, 32)) - let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; + let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; >expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 25, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 19)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 48)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 31)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 77)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 60)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 100)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 83)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 112)) - let assignable: { id: string, ...(T & U), ...(U & V) } = result; + let assignable: { ...(T & U), ...(U & V), id: string } = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 26, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 21)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 45)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 24, 7)) } function iteratedIntersectionUnion(t: T, u: U, v: V): void { @@ -188,31 +188,31 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { >U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) - let result = { id: 'bar', ...tu, ...uv }; + let result = { ...tu, ...uv, id: 'qux' }; >result : Symbol(result, Decl(objectSpreadIntersection.ts, 31, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 31, 18)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 31, 32)) - let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); + let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); >expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 32, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 20)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 49)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 32)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 74)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 55)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 103)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 86)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 115)) - let assignable: { id: string, ...(T & U), ...(U | V) } = result; + let assignable: { ...(T & U), ...(U | V), id: string } = result; >assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 33, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 21)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 45)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 31, 7)) } diff --git a/tests/baselines/reference/objectSpreadIntersection.types b/tests/baselines/reference/objectSpreadIntersection.types index 7700d8aa384d3..308200179166c 100644 --- a/tests/baselines/reference/objectSpreadIntersection.types +++ b/tests/baselines/reference/objectSpreadIntersection.types @@ -21,17 +21,16 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { >U : U >V : V - let result = { id: 'bar', ...tu, ...uv }; ->result : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) ->{ id: 'bar', ...tu, ...uv } : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) ->id : string ->'bar' : "bar" + let result = { ...tu, ...uv, id: 'foo' }; +>result : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) +>{ ...tu, ...uv, id: 'foo' } : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) >tu : any >uv : any - - let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); ->expected : ({ id: string; ...T; ...U } & { id: string; ...T; ...V }) | ({ id: string; ...U } & { id: string; ...U; ...V }) >id : string +>'foo' : "foo" + + let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); +>expected : ({ ...T; ...U; id: string; } & { ...T; ...V; id: string; }) | ({ ...U; id: string; } & { ...U; ...V; id: string; }) >T : T >U : U >id : string @@ -42,15 +41,16 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { >id : string >U : U >V : V - - let assignable: { id: string, ...(T | U), ...(U & V) } = result; ->assignable : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) >id : string + + let assignable: { ...(T | U), ...(U & V), id: string } = result; +>assignable : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) >T : T >U : U >U : U >V : V ->result : ({ id: string; ...T; ...U } | { id: string; ...U }) & ({ id: string; ...T; ...V } | { id: string; ...U; ...V }) +>id : string +>result : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) } // concrete types work interface A1 { a: number } @@ -101,30 +101,30 @@ function tripleIntersection(t: T, u: U, v: V): void { >U : U >V : V - let result = { id: 'foo', ...tuv }; ->result : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } ->{ id: 'foo', ...tuv } : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } ->id : string ->'foo' : "foo" + let result = { ...tuv, id: 'bar' }; +>result : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } +>{ ...tuv, id: 'bar' } : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } >tuv : any - - let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; ->expected : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } >id : string +>'bar' : "bar" + + let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; +>expected : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } >T : T >id : string >U : U >id : string >V : V ->result : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } - - let assignable: { id: string, ...(T & U & V) } = result; ->assignable : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } >id : string +>result : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } + + let assignable: { ...(T & U & V), id: string } = result; +>assignable : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } >T : T >U : U >V : V ->result : { id: string; ...T } & { id: string; ...U } & { id: string; ...V } +>id : string +>result : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } } function iteratedDoubleIntersection(t: T, u: U, v: V): void { >iteratedDoubleIntersection : (t: T, u: U, v: V) => void @@ -148,17 +148,16 @@ function iteratedDoubleIntersection(t: T, u: U, v: V): void { >U : U >V : V - let result = { id: 'bar', ...tu, ...uv }; ->result : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } ->{ id: 'bar', ...tu, ...uv } : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } ->id : string ->'bar' : "bar" + let result = { ...tu, ...uv, id: 'baz' }; +>result : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } +>{ ...tu, ...uv, id: 'baz' } : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } >tu : any >uv : any - - let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; ->expected : { id: string; ...T; ...U } & { id: string; ...T; ...V } & { id: string; ...U } & { id: string; ...U; ...V } >id : string +>'baz' : "baz" + + let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; +>expected : { ...T; ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; id: string; } & { ...U; ...V; id: string; } >T : T >U : U >id : string @@ -169,15 +168,16 @@ function iteratedDoubleIntersection(t: T, u: U, v: V): void { >id : string >U : U >V : V - - let assignable: { id: string, ...(T & U), ...(U & V) } = result; ->assignable : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } >id : string + + let assignable: { ...(T & U), ...(U & V), id: string } = result; +>assignable : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } >T : T >U : U >U : U >V : V ->result : { id: string; ...T; ...U } & { id: string; ...U } & { id: string; ...T; ...V } & { id: string; ...U; ...V } +>id : string +>result : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } } function iteratedIntersectionUnion(t: T, u: U, v: V): void { >iteratedIntersectionUnion : (t: T, u: U, v: V) => void @@ -201,17 +201,16 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { >U : U >V : V - let result = { id: 'bar', ...tu, ...uv }; ->result : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) ->{ id: 'bar', ...tu, ...uv } : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) ->id : string ->'bar' : "bar" + let result = { ...tu, ...uv, id: 'qux' }; +>result : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) +>{ ...tu, ...uv, id: 'qux' } : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) >tu : any >uv : any - - let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); ->expected : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) >id : string +>'qux' : "qux" + + let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); +>expected : ({ ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...V; id: string; }) >T : T >U : U >id : string @@ -222,15 +221,16 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { >id : string >U : U >V : V - - let assignable: { id: string, ...(T & U), ...(U | V) } = result; ->assignable : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) >id : string + + let assignable: { ...(T & U), ...(U | V), id: string } = result; +>assignable : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) >T : T >U : U >U : U >V : V ->result : ({ id: string; ...T; ...U } & { id: string; ...U }) | ({ id: string; ...T; ...V } & { id: string; ...U; ...V }) +>id : string +>result : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) } diff --git a/tests/baselines/reference/objectSpreadUnion.js b/tests/baselines/reference/objectSpreadUnion.js index 500b8a5ddc7ca..b3a114c772218 100644 --- a/tests/baselines/reference/objectSpreadUnion.js +++ b/tests/baselines/reference/objectSpreadUnion.js @@ -9,16 +9,16 @@ let assignable: { ...(A1 | A2) } = result; function tripleUnion(t: T, u: U, v: V): void { let tuv: T | U | V; - let result = { id: 'foo', ...tuv }; - let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; - let assignable: { id: string, ...(T | U | V) } = result; + let result = { ...tuv, id: 'foo' }; + let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; + let assignable: { ...(T | U | V), id: string } = result; } function iteratedDoubleUnion(t: T, u: U, v: V): void { let tu: T | U; let uv: U | V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; - let assignable: { id: string, ...(T | U), ...(U | V) } = result; + let result = { ...tu, ...uv, id: 'bar' }; + let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; + let assignable: { ...(T | U), ...(U | V), id: string } = result; } @@ -39,14 +39,14 @@ var sn = result.a; var assignable = result; function tripleUnion(t, u, v) { var tuv; - var result = __assign({ id: 'foo' }, tuv); + var result = __assign({}, tuv, { id: 'foo' }); var expected = result; var assignable = result; } function iteratedDoubleUnion(t, u, v) { var tu; var uv; - var result = __assign({ id: 'bar' }, tu, uv); + var result = __assign({}, tu, uv, { id: 'bar' }); var expected; var assignable = result; } diff --git a/tests/baselines/reference/objectSpreadUnion.symbols b/tests/baselines/reference/objectSpreadUnion.symbols index eea9e65185d0a..d630fde518b52 100644 --- a/tests/baselines/reference/objectSpreadUnion.symbols +++ b/tests/baselines/reference/objectSpreadUnion.symbols @@ -46,26 +46,26 @@ function tripleUnion(t: T, u: U, v: V): void { >U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) - let result = { id: 'foo', ...tuv }; + let result = { ...tuv, id: 'foo' }; >result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 10, 18)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 10, 26)) - let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; + let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; >expected : Symbol(expected, Decl(objectSpreadUnion.ts, 11, 7)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 19)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 42)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 25)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 65)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 48)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 71)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) - let assignable: { id: string, ...(T | U | V) } = result; + let assignable: { ...(T | U | V), id: string } = result; >assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 12, 7)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 12, 21)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 12, 37)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7)) } function iteratedDoubleUnion(t: T, u: U, v: V): void { @@ -90,31 +90,31 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) - let result = { id: 'bar', ...tu, ...uv }; + let result = { ...tu, ...uv, id: 'bar' }; >result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 17, 18)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 17, 32)) - let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; + let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; >expected : Symbol(expected, Decl(objectSpreadUnion.ts, 18, 7)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 19)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 48)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 31)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 77)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 60)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 100)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 83)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 112)) - let assignable: { id: string, ...(T | U), ...(U | V) } = result; + let assignable: { ...(T | U), ...(U | V), id: string } = result; >assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 19, 7)) ->id : Symbol(id, Decl(objectSpreadUnion.ts, 19, 21)) >T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31)) >V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34)) +>id : Symbol(id, Decl(objectSpreadUnion.ts, 19, 45)) >result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7)) } diff --git a/tests/baselines/reference/objectSpreadUnion.types b/tests/baselines/reference/objectSpreadUnion.types index 7cbffcf0a584c..5d8cdbae24a70 100644 --- a/tests/baselines/reference/objectSpreadUnion.types +++ b/tests/baselines/reference/objectSpreadUnion.types @@ -48,30 +48,30 @@ function tripleUnion(t: T, u: U, v: V): void { >U : U >V : V - let result = { id: 'foo', ...tuv }; ->result : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } ->{ id: 'foo', ...tuv } : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } + let result = { ...tuv, id: 'foo' }; +>result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } +>{ ...tuv, id: 'foo' } : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } +>tuv : any >id : string >'foo' : "foo" ->tuv : any - let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; ->expected : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } ->id : string + let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; +>expected : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } >T : T >id : string >U : U >id : string >V : V ->result : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } - - let assignable: { id: string, ...(T | U | V) } = result; ->assignable : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } >id : string +>result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } + + let assignable: { ...(T | U | V), id: string } = result; +>assignable : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } >T : T >U : U >V : V ->result : { id: string; ...T } | { id: string; ...U } | { id: string; ...V } +>id : string +>result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; } } function iteratedDoubleUnion(t: T, u: U, v: V): void { >iteratedDoubleUnion : (t: T, u: U, v: V) => void @@ -95,17 +95,16 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >U : U >V : V - let result = { id: 'bar', ...tu, ...uv }; ->result : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } ->{ id: 'bar', ...tu, ...uv } : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } ->id : string ->'bar' : "bar" + let result = { ...tu, ...uv, id: 'bar' }; +>result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } +>{ ...tu, ...uv, id: 'bar' } : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } >tu : any >uv : any - - let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; ->expected : { id: string; ...T; ...U } | { id: string; ...T; ...V } | { id: string; ...U } | { id: string; ...U; ...V } >id : string +>'bar' : "bar" + + let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; +>expected : { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; id: string; } | { ...U; ...V; id: string; } >T : T >U : U >id : string @@ -116,15 +115,16 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >id : string >U : U >V : V - - let assignable: { id: string, ...(T | U), ...(U | V) } = result; ->assignable : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } >id : string + + let assignable: { ...(T | U), ...(U | V), id: string } = result; +>assignable : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } >T : T >U : U >U : U >V : V ->result : { id: string; ...T; ...U } | { id: string; ...U } | { id: string; ...T; ...V } | { id: string; ...U; ...V } +>id : string +>result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } } diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index fc076e79543de..e35a84956c00a 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -83,8 +83,8 @@ let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } // generics -function f(t: T, u: U): { id: string, ...T, ...U } { - return { id: 'id', ...t, ...u }; +function f(t: T, u: U): { ...T, ...U, id: string } { + return { ...t, ...u, id: 'id' }; } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = f({ a: 1, b: 'yes' }, { c: 'no', d: false }) @@ -92,7 +92,7 @@ let overlap: { id: string, a: number, b: string } = f({ a: 1 }, { a: 2, b: 'extra' }) let overlapConflict: { id:string, a: string } = f({ a: 1 }, { a: 'mismatch' }) -let overwriteId: { id: boolean, a: number, c: number, d: string } = +let overwriteId: { id: string, a: number, c: number, d: string } = f({ a: 1, id: true }, { c: 1, d: 'no' }) class D { m() { }; q = 2; } diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts index e3bd1ab7bb32a..63e9f00aaae62 100644 --- a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts +++ b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts @@ -13,34 +13,36 @@ function f(t: T, u: U, v: V): void { const missingU: { ...T, ...V } = o; // error, missing U const missingV: { ...T, ...U } = o; // error, missing V const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok - const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // ok + const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // error, not assignable const emptyTarget: { } = { ...t, ...u } // ok const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) + // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to + // T ... { sn?: number | string | boolean } let optionalNumber: { sn?: number }; let optionalString: { sn?: string }; let optionalBoolean: { sn?: boolean }; const unionCutoff: { ...T, sn?: number | string | boolean } = - { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } // ok + { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } unionCutoff.sn; // ok const optionalCutoff = { ...t, ...optionalNumber }; // ok optionalCutoff.sn; // ok const interspersed: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // ok + { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable const interspersedMissingU: { first: string, second: string, ...T, third: string } = { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // ok + { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = - { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, 'first' not found + { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, 'second' not found + { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, 'third' not found + { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable } diff --git a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts index 6471e622b68a4..f70995cb4b2fc 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts @@ -1,9 +1,9 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { let tu: T | U; let uv: U & V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: ({ id: string, ...T, ...U } & { id: string, ...T, ...V }) | ({ id: string, ...U } & { id: string, ...U, ...V }); - let assignable: { id: string, ...(T | U), ...(U & V) } = result; + let result = { ...tu, ...uv, id: 'foo' }; + let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); + let assignable: { ...(T | U), ...(U & V), id: string } = result; } // concrete types work interface A1 { a: number } @@ -15,22 +15,22 @@ let assignable: { ...(A1 & A2) } = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; - let result = { id: 'foo', ...tuv }; - let expected: { id: string, ...T } & { id: string, ...U } & { id: string, ...V } = result; - let assignable: { id: string, ...(T & U & V) } = result; + let result = { ...tuv, id: 'bar' }; + let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; + let assignable: { ...(T & U & V), id: string } = result; } function iteratedDoubleIntersection(t: T, u: U, v: V): void { let tu: T & U; let uv: U & V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: { id: string, ...T, ...U } & { id: string, ...T, ...V } & { id: string, ...U } & { id: string, ...U, ...V }; - let assignable: { id: string, ...(T & U), ...(U & V) } = result; + let result = { ...tu, ...uv, id: 'baz' }; + let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; + let assignable: { ...(T & U), ...(U & V), id: string } = result; } function iteratedIntersectionUnion(t: T, u: U, v: V): void { let tu: T & U; let uv: U | V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: ({ id: string, ...T, ...U } & { id: string, ...U }) | ({ id: string, ...T, ...V } & { id: string, ...U, ...V }); - let assignable: { id: string, ...(T & U), ...(U | V) } = result; + let result = { ...tu, ...uv, id: 'qux' }; + let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); + let assignable: { ...(T & U), ...(U | V), id: string } = result; } diff --git a/tests/cases/conformance/types/spread/objectSpreadUnion.ts b/tests/cases/conformance/types/spread/objectSpreadUnion.ts index 03a4251ca8172..cd490d76bdaf4 100644 --- a/tests/cases/conformance/types/spread/objectSpreadUnion.ts +++ b/tests/cases/conformance/types/spread/objectSpreadUnion.ts @@ -8,16 +8,16 @@ let assignable: { ...(A1 | A2) } = result; function tripleUnion(t: T, u: U, v: V): void { let tuv: T | U | V; - let result = { id: 'foo', ...tuv }; - let expected: { id: string, ...T } | { id: string, ...U } | { id: string, ...V } = result; - let assignable: { id: string, ...(T | U | V) } = result; + let result = { ...tuv, id: 'foo' }; + let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; + let assignable: { ...(T | U | V), id: string } = result; } function iteratedDoubleUnion(t: T, u: U, v: V): void { let tu: T | U; let uv: U | V; - let result = { id: 'bar', ...tu, ...uv }; - let expected: { id: string, ...T, ...U } | { id: string, ...T, ...V } | { id: string, ...U } | { id: string, ...U, ...V }; - let assignable: { id: string, ...(T | U), ...(U | V) } = result; + let result = { ...tu, ...uv, id: 'bar' }; + let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; + let assignable: { ...(T | U), ...(U | V), id: string } = result; } From 76d194440c2586557b73bb15cb40dd9550ff3a0b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 20 Oct 2016 09:06:36 -0700 Subject: [PATCH 40/85] Spread no longer distributes intersections --- src/compiler/checker.ts | 18 ++++-------------- src/compiler/types.ts | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e3651f6cf3014..f0ad77cd5c471 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5810,11 +5810,6 @@ namespace ts { types.push(rspread.right); return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); } - if (right.flags & TypeFlags.Intersection) { - const spreads = map((right as IntersectionType).types, - t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); - return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments); - } if (right.flags & TypeFlags.Union) { const spreads = map((right as UnionType).types, t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); @@ -5840,11 +5835,6 @@ namespace ts { const simplified = getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments); return getSpreadType([(left as SpreadType).left, simplified], symbol, aliasSymbol, aliasTypeArguments); } - if (left.flags & TypeFlags.Intersection) { - const spreads = map((left as IntersectionType).types, - t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); - return getIntersectionType(spreads, aliasSymbol, aliasTypeArguments); - } if (left.flags & TypeFlags.Union) { const spreads = map((left as UnionType).types, t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); @@ -5901,9 +5891,9 @@ namespace ts { } const spread = spreadTypes[id] = createObjectType(TypeFlags.Spread, symbol) as SpreadType; Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.ObjectType)), "Left flags: " + left.flags.toString(2)); - Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.ObjectType)), "Right flags: " + right.flags.toString(2)); + Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.Intersection | TypeFlags.ObjectType)), "Right flags: " + right.flags.toString(2)); spread.left = left as SpreadType | ResolvedType; - spread.right = right as TypeParameter | ResolvedType; + spread.right = right as TypeParameter | IntersectionType | ResolvedType; spread.aliasSymbol = aliasSymbol; spread.aliasTypeArguments = aliasTypeArguments; return spread; @@ -6953,11 +6943,11 @@ namespace ts { spreadTypeRelatedTo(source.right.flags & TypeFlags.ObjectType ? source.left as SpreadType : source, target.right.flags & TypeFlags.ObjectType ? target.left as SpreadType : target); } - // If both right sides are type parameters, then they must be identical for the spread types to be related. + // If both right sides are type parameters or intersections, then they must be identical for the spread types to be related. // It also means that the left sides are either spread types or object types. // if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed - if (target.right.symbol !== source.right.symbol) { + if (target.right !== source.right) { return false; } if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 10c9abbd1ca21..3dbfba72acbd0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2780,7 +2780,7 @@ namespace ts { /* @internal */ export interface SpreadType extends Type { left: SpreadType | ResolvedType; - right: TypeParameter | ResolvedType; + right: TypeParameter | IntersectionType | ResolvedType; } /* @internal */ From d9afa34be18a2ab55a321f605de78315fbb57143 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 20 Oct 2016 09:07:01 -0700 Subject: [PATCH 41/85] Update spread w/intersection tests --- .../reference/objectSpreadIntersection.js | 8 - .../objectSpreadIntersection.symbols | 232 +++++++----------- .../reference/objectSpreadIntersection.types | 94 ++----- .../reference/objectSpreadNegative.errors.txt | 14 +- .../reference/objectSpreadNegative.js | 14 +- .../types/spread/objectSpreadIntersection.ts | 4 - .../types/spread/objectSpreadNegative.ts | 7 +- 7 files changed, 136 insertions(+), 237 deletions(-) diff --git a/tests/baselines/reference/objectSpreadIntersection.js b/tests/baselines/reference/objectSpreadIntersection.js index 0a7f1ddfcee43..d86b7bfca584c 100644 --- a/tests/baselines/reference/objectSpreadIntersection.js +++ b/tests/baselines/reference/objectSpreadIntersection.js @@ -3,7 +3,6 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { let tu: T | U; let uv: U & V; let result = { ...tu, ...uv, id: 'foo' }; - let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); let assignable: { ...(T | U), ...(U & V), id: string } = result; } // concrete types work @@ -17,21 +16,18 @@ let assignable: { ...(A1 & A2) } = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; let result = { ...tuv, id: 'bar' }; - let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; let assignable: { ...(T & U & V), id: string } = result; } function iteratedDoubleIntersection(t: T, u: U, v: V): void { let tu: T & U; let uv: U & V; let result = { ...tu, ...uv, id: 'baz' }; - let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; let assignable: { ...(T & U), ...(U & V), id: string } = result; } function iteratedIntersectionUnion(t: T, u: U, v: V): void { let tu: T & U; let uv: U | V; let result = { ...tu, ...uv, id: 'qux' }; - let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); let assignable: { ...(T & U), ...(U | V), id: string } = result; } @@ -50,7 +46,6 @@ function iteratedUnionIntersection(t, u, v) { var tu; var uv; var result = __assign({}, tu, uv, { id: 'foo' }); - var expected; var assignable = result; } var a12; @@ -60,20 +55,17 @@ var assignable = result; function tripleIntersection(t, u, v) { var tuv; var result = __assign({}, tuv, { id: 'bar' }); - var expected = result; var assignable = result; } function iteratedDoubleIntersection(t, u, v) { var tu; var uv; var result = __assign({}, tu, uv, { id: 'baz' }); - var expected; var assignable = result; } function iteratedIntersectionUnion(t, u, v) { var tu; var uv; var result = __assign({}, tu, uv, { id: 'qux' }); - var expected; var assignable = result; } diff --git a/tests/baselines/reference/objectSpreadIntersection.symbols b/tests/baselines/reference/objectSpreadIntersection.symbols index c59c37670b25d..6dd27645ddf13 100644 --- a/tests/baselines/reference/objectSpreadIntersection.symbols +++ b/tests/baselines/reference/objectSpreadIntersection.symbols @@ -25,195 +25,143 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { >result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) >id : Symbol(id, Decl(objectSpreadIntersection.ts, 3, 32)) - let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); ->expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 4, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 32)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 61)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 86)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 115)) - let assignable: { ...(T | U), ...(U & V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 5, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 4, 7)) >T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37)) >V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 5, 45)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 45)) >result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7)) } // concrete types work interface A1 { a: number } ->A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 6, 1)) ->a : Symbol(A1.a, Decl(objectSpreadIntersection.ts, 8, 14)) +>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1)) +>a : Symbol(A1.a, Decl(objectSpreadIntersection.ts, 7, 14)) interface A2 { a: string } ->A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 8, 26)) ->a : Symbol(A2.a, Decl(objectSpreadIntersection.ts, 9, 14)) +>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) +>a : Symbol(A2.a, Decl(objectSpreadIntersection.ts, 8, 14)) let a12: A1 & A2; ->a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 10, 3)) ->A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 6, 1)) ->A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 8, 26)) +>a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 9, 3)) +>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1)) +>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) let result = { ...a12 }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 11, 3)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 10, 3)) let sn: number & string = result.a; ->sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 12, 3)) ->result.a : Symbol(a, Decl(objectSpreadIntersection.ts, 8, 14), Decl(objectSpreadIntersection.ts, 9, 14)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 11, 3)) ->a : Symbol(a, Decl(objectSpreadIntersection.ts, 8, 14), Decl(objectSpreadIntersection.ts, 9, 14)) +>sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 11, 3)) +>result.a : Symbol(a, Decl(objectSpreadIntersection.ts, 7, 14), Decl(objectSpreadIntersection.ts, 8, 14)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 10, 3)) +>a : Symbol(a, Decl(objectSpreadIntersection.ts, 7, 14), Decl(objectSpreadIntersection.ts, 8, 14)) let assignable: { ...(A1 & A2) } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 13, 3)) ->A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 6, 1)) ->A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 8, 26)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 11, 3)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 12, 3)) +>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1)) +>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 10, 3)) function tripleIntersection(t: T, u: U, v: V): void { ->tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 13, 42)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) ->t : Symbol(t, Decl(objectSpreadIntersection.ts, 15, 37)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) ->u : Symbol(u, Decl(objectSpreadIntersection.ts, 15, 42)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) ->v : Symbol(v, Decl(objectSpreadIntersection.ts, 15, 48)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 12, 42)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 14, 37)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 14, 42)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 14, 48)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) let tuv: T & U & V; ->tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 16, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) +>tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 15, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) let result = { ...tuv, id: 'bar' }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 17, 26)) - - let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; ->expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 18, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 25)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 48)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 18, 71)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 16, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 16, 26)) let assignable: { ...(T & U & V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 19, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 15, 28)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 15, 30)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 15, 33)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 19, 37)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 17, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 17, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 17, 37)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 16, 7)) } function iteratedDoubleIntersection(t: T, u: U, v: V): void { ->iteratedDoubleIntersection : Symbol(iteratedDoubleIntersection, Decl(objectSpreadIntersection.ts, 20, 1)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) ->t : Symbol(t, Decl(objectSpreadIntersection.ts, 21, 45)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) ->u : Symbol(u, Decl(objectSpreadIntersection.ts, 21, 50)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->v : Symbol(v, Decl(objectSpreadIntersection.ts, 21, 56)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>iteratedDoubleIntersection : Symbol(iteratedDoubleIntersection, Decl(objectSpreadIntersection.ts, 18, 1)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 19, 45)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 19, 50)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 19, 56)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) let tu: T & U; ->tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 22, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 20, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) let uv: U & V; ->uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 23, 7)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 21, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) let result = { ...tu, ...uv, id: 'baz' }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 24, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 24, 32)) - - let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; ->expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 25, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 31)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 60)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 83)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 25, 112)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 22, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 22, 32)) let assignable: { ...(T & U), ...(U & V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 26, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 21, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 21, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 21, 41)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 45)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 24, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 23, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 23, 45)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 22, 7)) } function iteratedIntersectionUnion(t: T, u: U, v: V): void { ->iteratedIntersectionUnion : Symbol(iteratedIntersectionUnion, Decl(objectSpreadIntersection.ts, 27, 1)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) ->t : Symbol(t, Decl(objectSpreadIntersection.ts, 28, 44)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) ->u : Symbol(u, Decl(objectSpreadIntersection.ts, 28, 49)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->v : Symbol(v, Decl(objectSpreadIntersection.ts, 28, 55)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>iteratedIntersectionUnion : Symbol(iteratedIntersectionUnion, Decl(objectSpreadIntersection.ts, 24, 1)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 25, 44)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 25, 49)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 25, 55)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) let tu: T & U; ->tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 29, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 26, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) let uv: U | V; ->uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 30, 7)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 27, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) let result = { ...tu, ...uv, id: 'qux' }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 31, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 31, 32)) - - let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); ->expected : Symbol(expected, Decl(objectSpreadIntersection.ts, 32, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 32)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 55)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 86)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 115)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 28, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 28, 32)) let assignable: { ...(T & U), ...(U | V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 33, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 28, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 28, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 28, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 45)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 31, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 29, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 29, 45)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 28, 7)) } diff --git a/tests/baselines/reference/objectSpreadIntersection.types b/tests/baselines/reference/objectSpreadIntersection.types index 308200179166c..0e21f42a76bea 100644 --- a/tests/baselines/reference/objectSpreadIntersection.types +++ b/tests/baselines/reference/objectSpreadIntersection.types @@ -22,35 +22,21 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'foo' }; ->result : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) ->{ ...tu, ...uv, id: 'foo' } : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) +>result : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } +>{ ...tu, ...uv, id: 'foo' } : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } >tu : any >uv : any >id : string >'foo' : "foo" - let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); ->expected : ({ ...T; ...U; id: string; } & { ...T; ...V; id: string; }) | ({ ...U; id: string; } & { ...U; ...V; id: string; }) ->T : T ->U : U ->id : string ->T : T ->V : V ->id : string ->U : U ->id : string ->U : U ->V : V ->id : string - let assignable: { ...(T | U), ...(U & V), id: string } = result; ->assignable : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) +>assignable : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } >T : T >U : U >U : U >V : V >id : string ->result : ({ ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...U; ...T; ...U; id: string; }) & ({ ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } | { ...T; ...U; ...T; ...V; id: string; } | { ...U; ...T; ...U; ...V; id: string; }) +>result : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; } } // concrete types work interface A1 { a: number } @@ -67,21 +53,21 @@ let a12: A1 & A2; >A2 : A2 let result = { ...a12 }; ->result : { a: number; } & { a: string; } ->{ ...a12 } : { a: number; } & { a: string; } +>result : { ...A1 & A2 } +>{ ...a12 } : { ...A1 & A2 } >a12 : any let sn: number & string = result.a; >sn : number & string >result.a : number & string ->result : { a: number; } & { a: string; } +>result : { ...A1 & A2 } >a : number & string let assignable: { ...(A1 & A2) } = result; ->assignable : { a: number; } & { a: string; } +>assignable : { ...A1 & A2 } >A1 : A1 >A2 : A2 ->result : { a: number; } & { a: string; } +>result : { ...A1 & A2 } function tripleIntersection(t: T, u: U, v: V): void { >tripleIntersection : (t: T, u: U, v: V) => void @@ -102,29 +88,19 @@ function tripleIntersection(t: T, u: U, v: V): void { >V : V let result = { ...tuv, id: 'bar' }; ->result : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } ->{ ...tuv, id: 'bar' } : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } +>result : { ...T & U & V; id: string; } +>{ ...tuv, id: 'bar' } : { ...T & U & V; id: string; } >tuv : any >id : string >'bar' : "bar" - let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; ->expected : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } ->T : T ->id : string ->U : U ->id : string ->V : V ->id : string ->result : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } - let assignable: { ...(T & U & V), id: string } = result; ->assignable : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } +>assignable : { ...T & U & V; id: string; } >T : T >U : U >V : V >id : string ->result : { ...T; id: string; } & { ...U; id: string; } & { ...V; id: string; } +>result : { ...T & U & V; id: string; } } function iteratedDoubleIntersection(t: T, u: U, v: V): void { >iteratedDoubleIntersection : (t: T, u: U, v: V) => void @@ -149,35 +125,21 @@ function iteratedDoubleIntersection(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'baz' }; ->result : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } ->{ ...tu, ...uv, id: 'baz' } : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } +>result : { ...T & U; ...U & V; id: string; } +>{ ...tu, ...uv, id: 'baz' } : { ...T & U; ...U & V; id: string; } >tu : any >uv : any >id : string >'baz' : "baz" - let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; ->expected : { ...T; ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; id: string; } & { ...U; ...V; id: string; } ->T : T ->U : U ->id : string ->T : T ->V : V ->id : string ->U : U ->id : string ->U : U ->V : V ->id : string - let assignable: { ...(T & U), ...(U & V), id: string } = result; ->assignable : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } +>assignable : { ...T & U; ...U & V; id: string; } >T : T >U : U >U : U >V : V >id : string ->result : { ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...U; id: string; } & { ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; } +>result : { ...T & U; ...U & V; id: string; } } function iteratedIntersectionUnion(t: T, u: U, v: V): void { >iteratedIntersectionUnion : (t: T, u: U, v: V) => void @@ -202,35 +164,21 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'qux' }; ->result : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) ->{ ...tu, ...uv, id: 'qux' } : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) +>result : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } +>{ ...tu, ...uv, id: 'qux' } : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } >tu : any >uv : any >id : string >'qux' : "qux" - let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); ->expected : ({ ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...V; id: string; }) ->T : T ->U : U ->id : string ->U : U ->id : string ->T : T ->V : V ->id : string ->U : U ->V : V ->id : string - let assignable: { ...(T & U), ...(U | V), id: string } = result; ->assignable : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) +>assignable : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } >T : T >U : U >U : U >V : V >id : string ->result : ({ ...T; ...U; id: string; } & { ...U; ...T; ...U; id: string; } & { ...T; ...U; ...T; ...U; id: string; } & { ...U; id: string; }) | ({ ...T; ...V; id: string; } & { ...U; ...T; ...V; id: string; } & { ...T; ...U; ...T; ...V; id: string; } & { ...T; ...U; ...V; id: string; } & { ...U; ...T; ...U; ...V; id: string; } & { ...U; ...V; id: string; }) +>result : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } } diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index b79354c4a9487..64928782280ae 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -18,10 +18,11 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,12): error TS233 tests/cases/conformance/types/spread/objectSpreadNegative.ts(55,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(63,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,9): error TS2322: Type '{ ...T & V }' is not assignable to type '{ ...T & U }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (18 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (19 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -119,8 +120,13 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(63,12): error TS232 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. - // { ...U } is not assignable to U - function override(initial: U, override: U): U { + function override(initial: U, override: U, t: T, v: V): U { + // { ... T & V } is not assignable to { ... T & U } + let tvs: { ...T & V }; + let mistake: { ...T & U } = tvs; + ~~~~~~~ +!!! error TS2322: Type '{ ...T & V }' is not assignable to type '{ ...T & U }'. + // { ...U } is not assignable to U return { ...initial, ...override }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2322: Type '{ ...U }' is not assignable to type 'U'. diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 452ec457e9ae3..7187b6009bd39 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -59,8 +59,11 @@ let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: numb callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature -// { ...U } is not assignable to U -function override(initial: U, override: U): U { +function override(initial: U, override: U, t: T, v: V): U { + // { ... T & V } is not assignable to { ... T & U } + let tvs: { ...T & V }; + let mistake: { ...T & U } = tvs; + // { ...U } is not assignable to U return { ...initial, ...override }; } @@ -133,7 +136,10 @@ spreadC.m(); // error 'm' is not in '{ ... c }' var callableConstructableSpread; callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature -// { ...U } is not assignable to U -function override(initial, override) { +function override(initial, override, t, v) { + // { ... T & V } is not assignable to { ... T & U } + var tvs; + var mistake = tvs; + // { ...U } is not assignable to U return __assign({}, initial, override); } diff --git a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts index f70995cb4b2fc..636283dd71545 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts @@ -2,7 +2,6 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { let tu: T | U; let uv: U & V; let result = { ...tu, ...uv, id: 'foo' }; - let expected: ({ ...T, ...U, id: string } & { ...T, ...V, id: string }) | ({ ...U, id: string } & { ...U, ...V, id: string }); let assignable: { ...(T | U), ...(U & V), id: string } = result; } // concrete types work @@ -16,21 +15,18 @@ let assignable: { ...(A1 & A2) } = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; let result = { ...tuv, id: 'bar' }; - let expected: { ...T, id: string } & { ...U, id: string } & { ...V, id: string } = result; let assignable: { ...(T & U & V), id: string } = result; } function iteratedDoubleIntersection(t: T, u: U, v: V): void { let tu: T & U; let uv: U & V; let result = { ...tu, ...uv, id: 'baz' }; - let expected: { ...T, ...U, id: string } & { ...T, ...V, id: string } & { ...U, id: string } & { ...U, ...V, id: string }; let assignable: { ...(T & U), ...(U & V), id: string } = result; } function iteratedIntersectionUnion(t: T, u: U, v: V): void { let tu: T & U; let uv: U | V; let result = { ...tu, ...uv, id: 'qux' }; - let expected: ({ ...T, ...U, id: string } & { ...U, id: string }) | ({ ...T, ...V, id: string } & { ...U, ...V, id: string }); let assignable: { ...(T & U), ...(U | V), id: string } = result; } diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 04a88d2a42738..146ab072bbf17 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -59,7 +59,10 @@ let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: numb callableConstructableSpread(12); // error, no call signature new callableConstructableSpread(12); // error, no construct signature -// { ...U } is not assignable to U -function override(initial: U, override: U): U { +function override(initial: U, override: U, t: T, v: V): U { + // { ... T & V } is not assignable to { ... T & U } + let tvs: { ...T & V }; + let mistake: { ...T & U } = tvs; + // { ...U } is not assignable to U return { ...initial, ...override }; } From ce61b341599263f2caf68f34c644038f410ddb76 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 21 Oct 2016 10:53:19 -0700 Subject: [PATCH 42/85] Resolve all-object intersections inside spreads This means that getSpreadType will return an object type, even when spreading two intersections, as long as those intersections contain nothing but object types themselves. --- src/compiler/checker.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf81d64ea0622..5da7cc7e66786 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5828,13 +5828,16 @@ namespace ts { types.push(rspread.right); return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); } + if (right.flags & TypeFlags.Intersection) { + right = resolveObjectIntersection(right as IntersectionType); + } if (right.flags & TypeFlags.Union) { const spreads = map((right as UnionType).types, t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } const atBeginning = types.length === 0; - const left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); + let left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); if (right.flags & (TypeFlags.Primitive & ~TypeFlags.StringLike) || left.flags & TypeFlags.Any) { return left; } @@ -5853,6 +5856,9 @@ namespace ts { const simplified = getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments); return getSpreadType([(left as SpreadType).left, simplified], symbol, aliasSymbol, aliasTypeArguments); } + if (left.flags & TypeFlags.Intersection) { + left = resolveObjectIntersection(left as IntersectionType); + } if (left.flags & TypeFlags.Union) { const spreads = map((left as UnionType).types, t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); @@ -5917,6 +5923,20 @@ namespace ts { return spread; } + function resolveObjectIntersection(intersection: IntersectionType): IntersectionType | ResolvedType { + if (find(intersection.types, t => !(t.flags & TypeFlags.ObjectType && !couldContainTypeParameters(t)))) { + return intersection; + } + const properties = getPropertiesOfType(intersection); + const members = createMap(); + for (const property of properties) { + members[property.name] = property; + } + const stringIndex = getIndexInfoOfType(intersection, IndexKind.String); + const numberIndex = getIndexInfoOfType(intersection, IndexKind.Number); + return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndex, numberIndex); + } + function createLiteralType(flags: TypeFlags, text: string) { const type = createType(flags); type.text = text; From 422f73b1a99eedc80dd70a7d97c49467b05172e3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 21 Oct 2016 10:54:53 -0700 Subject: [PATCH 43/85] Update and improve spread intersection tests --- .../reference/objectSpreadIntersection.js | 12 +- .../objectSpreadIntersection.symbols | 181 ++++++++++-------- .../reference/objectSpreadIntersection.types | 37 +++- .../types/spread/objectSpreadIntersection.ts | 8 +- 4 files changed, 146 insertions(+), 92 deletions(-) diff --git a/tests/baselines/reference/objectSpreadIntersection.js b/tests/baselines/reference/objectSpreadIntersection.js index d86b7bfca584c..2ec6ad35413a3 100644 --- a/tests/baselines/reference/objectSpreadIntersection.js +++ b/tests/baselines/reference/objectSpreadIntersection.js @@ -8,10 +8,14 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { // concrete types work interface A1 { a: number } interface A2 { a: string } +interface B1 { b: number } +interface B2 { b: string } let a12: A1 & A2; -let result = { ...a12 }; +let b12: B1 & B2; +let result = { ...a12, ...b12 }; let sn: number & string = result.a; -let assignable: { ...(A1 & A2) } = result; +sn = result.b; +let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; @@ -49,8 +53,10 @@ function iteratedUnionIntersection(t, u, v) { var assignable = result; } var a12; -var result = __assign({}, a12); +var b12; +var result = __assign({}, a12, b12); var sn = result.a; +sn = result.b; var assignable = result; function tripleIntersection(t, u, v) { var tuv; diff --git a/tests/baselines/reference/objectSpreadIntersection.symbols b/tests/baselines/reference/objectSpreadIntersection.symbols index 6dd27645ddf13..bc63cb11348e4 100644 --- a/tests/baselines/reference/objectSpreadIntersection.symbols +++ b/tests/baselines/reference/objectSpreadIntersection.symbols @@ -43,125 +43,146 @@ interface A2 { a: string } >A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) >a : Symbol(A2.a, Decl(objectSpreadIntersection.ts, 8, 14)) +interface B1 { b: number } +>B1 : Symbol(B1, Decl(objectSpreadIntersection.ts, 8, 26)) +>b : Symbol(B1.b, Decl(objectSpreadIntersection.ts, 9, 14)) + +interface B2 { b: string } +>B2 : Symbol(B2, Decl(objectSpreadIntersection.ts, 9, 26)) +>b : Symbol(B2.b, Decl(objectSpreadIntersection.ts, 10, 14)) + let a12: A1 & A2; ->a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 9, 3)) +>a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 11, 3)) >A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1)) >A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) -let result = { ...a12 }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 10, 3)) +let b12: B1 & B2; +>b12 : Symbol(b12, Decl(objectSpreadIntersection.ts, 12, 3)) +>B1 : Symbol(B1, Decl(objectSpreadIntersection.ts, 8, 26)) +>B2 : Symbol(B2, Decl(objectSpreadIntersection.ts, 9, 26)) + +let result = { ...a12, ...b12 }; +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) let sn: number & string = result.a; ->sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 11, 3)) +>sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 14, 3)) >result.a : Symbol(a, Decl(objectSpreadIntersection.ts, 7, 14), Decl(objectSpreadIntersection.ts, 8, 14)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 10, 3)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) >a : Symbol(a, Decl(objectSpreadIntersection.ts, 7, 14), Decl(objectSpreadIntersection.ts, 8, 14)) -let assignable: { ...(A1 & A2) } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 12, 3)) +sn = result.b; +>sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 14, 3)) +>result.b : Symbol(b, Decl(objectSpreadIntersection.ts, 9, 14), Decl(objectSpreadIntersection.ts, 10, 14)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) +>b : Symbol(b, Decl(objectSpreadIntersection.ts, 9, 14), Decl(objectSpreadIntersection.ts, 10, 14)) + +let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 16, 3)) >A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1)) >A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 10, 3)) +>B1 : Symbol(B1, Decl(objectSpreadIntersection.ts, 8, 26)) +>B2 : Symbol(B2, Decl(objectSpreadIntersection.ts, 9, 26)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3)) function tripleIntersection(t: T, u: U, v: V): void { ->tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 12, 42)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) ->t : Symbol(t, Decl(objectSpreadIntersection.ts, 14, 37)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) ->u : Symbol(u, Decl(objectSpreadIntersection.ts, 14, 42)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) ->v : Symbol(v, Decl(objectSpreadIntersection.ts, 14, 48)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) +>tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 16, 56)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 18, 37)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 18, 42)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 18, 48)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33)) let tuv: T & U & V; ->tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 15, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) +>tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 19, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33)) let result = { ...tuv, id: 'bar' }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 16, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 16, 26)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 20, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 20, 26)) let assignable: { ...(T & U & V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 17, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 14, 28)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 14, 30)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 14, 33)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 17, 37)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 16, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 21, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 21, 37)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 20, 7)) } function iteratedDoubleIntersection(t: T, u: U, v: V): void { ->iteratedDoubleIntersection : Symbol(iteratedDoubleIntersection, Decl(objectSpreadIntersection.ts, 18, 1)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) ->t : Symbol(t, Decl(objectSpreadIntersection.ts, 19, 45)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) ->u : Symbol(u, Decl(objectSpreadIntersection.ts, 19, 50)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) ->v : Symbol(v, Decl(objectSpreadIntersection.ts, 19, 56)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) +>iteratedDoubleIntersection : Symbol(iteratedDoubleIntersection, Decl(objectSpreadIntersection.ts, 22, 1)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 23, 45)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 23, 50)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 23, 56)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41)) let tu: T & U; ->tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 20, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 24, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) let uv: U & V; ->uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 21, 7)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 25, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41)) let result = { ...tu, ...uv, id: 'baz' }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 22, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 22, 32)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 26, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 32)) let assignable: { ...(T & U), ...(U & V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 23, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 19, 36)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 19, 38)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 19, 41)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 23, 45)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 22, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 27, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 27, 45)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 26, 7)) } function iteratedIntersectionUnion(t: T, u: U, v: V): void { ->iteratedIntersectionUnion : Symbol(iteratedIntersectionUnion, Decl(objectSpreadIntersection.ts, 24, 1)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) ->t : Symbol(t, Decl(objectSpreadIntersection.ts, 25, 44)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) ->u : Symbol(u, Decl(objectSpreadIntersection.ts, 25, 49)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) ->v : Symbol(v, Decl(objectSpreadIntersection.ts, 25, 55)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) +>iteratedIntersectionUnion : Symbol(iteratedIntersectionUnion, Decl(objectSpreadIntersection.ts, 28, 1)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40)) +>t : Symbol(t, Decl(objectSpreadIntersection.ts, 29, 44)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35)) +>u : Symbol(u, Decl(objectSpreadIntersection.ts, 29, 49)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) +>v : Symbol(v, Decl(objectSpreadIntersection.ts, 29, 55)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40)) let tu: T & U; ->tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 26, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) +>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 30, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) let uv: U | V; ->uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 27, 7)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) +>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 31, 7)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40)) let result = { ...tu, ...uv, id: 'qux' }; ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 28, 7)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 28, 32)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 32, 7)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 32)) let assignable: { ...(T & U), ...(U | V), id: string } = result; ->assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 29, 7)) ->T : Symbol(T, Decl(objectSpreadIntersection.ts, 25, 35)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) ->U : Symbol(U, Decl(objectSpreadIntersection.ts, 25, 37)) ->V : Symbol(V, Decl(objectSpreadIntersection.ts, 25, 40)) ->id : Symbol(id, Decl(objectSpreadIntersection.ts, 29, 45)) ->result : Symbol(result, Decl(objectSpreadIntersection.ts, 28, 7)) +>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 33, 7)) +>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) +>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37)) +>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40)) +>id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 45)) +>result : Symbol(result, Decl(objectSpreadIntersection.ts, 32, 7)) } diff --git a/tests/baselines/reference/objectSpreadIntersection.types b/tests/baselines/reference/objectSpreadIntersection.types index 0e21f42a76bea..13c1384698f08 100644 --- a/tests/baselines/reference/objectSpreadIntersection.types +++ b/tests/baselines/reference/objectSpreadIntersection.types @@ -47,27 +47,50 @@ interface A2 { a: string } >A2 : A2 >a : string +interface B1 { b: number } +>B1 : B1 +>b : number + +interface B2 { b: string } +>B2 : B2 +>b : string + let a12: A1 & A2; >a12 : A1 & A2 >A1 : A1 >A2 : A2 -let result = { ...a12 }; ->result : { ...A1 & A2 } ->{ ...a12 } : { ...A1 & A2 } +let b12: B1 & B2; +>b12 : B1 & B2 +>B1 : B1 +>B2 : B2 + +let result = { ...a12, ...b12 }; +>result : { b: number & string; a: number & string; } +>{ ...a12, ...b12 } : { b: number & string; a: number & string; } >a12 : any +>b12 : any let sn: number & string = result.a; >sn : number & string >result.a : number & string ->result : { ...A1 & A2 } +>result : { b: number & string; a: number & string; } >a : number & string -let assignable: { ...(A1 & A2) } = result; ->assignable : { ...A1 & A2 } +sn = result.b; +>sn = result.b : number & string +>sn : number & string +>result.b : number & string +>result : { b: number & string; a: number & string; } +>b : number & string + +let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; +>assignable : { b: number & string; a: number & string; } >A1 : A1 >A2 : A2 ->result : { ...A1 & A2 } +>B1 : B1 +>B2 : B2 +>result : { b: number & string; a: number & string; } function tripleIntersection(t: T, u: U, v: V): void { >tripleIntersection : (t: T, u: U, v: V) => void diff --git a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts index 636283dd71545..3bedacca89fac 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts @@ -7,10 +7,14 @@ function iteratedUnionIntersection(t: T, u: U, v: V): void { // concrete types work interface A1 { a: number } interface A2 { a: string } +interface B1 { b: number } +interface B2 { b: string } let a12: A1 & A2; -let result = { ...a12 }; +let b12: B1 & B2; +let result = { ...a12, ...b12 }; let sn: number & string = result.a; -let assignable: { ...(A1 & A2) } = result; +sn = result.b; +let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; function tripleIntersection(t: T, u: U, v: V): void { let tuv: T & U & V; From fdfb159024047fff8980391653cda6419046fa36 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 21 Oct 2016 13:38:24 -0700 Subject: [PATCH 44/85] Simplify expression in resolveObjectIntersection --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5da7cc7e66786..9df086f1bb70f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5924,7 +5924,7 @@ namespace ts { } function resolveObjectIntersection(intersection: IntersectionType): IntersectionType | ResolvedType { - if (find(intersection.types, t => !(t.flags & TypeFlags.ObjectType && !couldContainTypeParameters(t)))) { + if (find(intersection.types, t => !(t.flags & TypeFlags.ObjectType) || couldContainTypeParameters(t))) { return intersection; } const properties = getPropertiesOfType(intersection); From ff92afd47bd6a5295cd84e129fea7212f65e3283 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 21 Oct 2016 16:27:32 -0700 Subject: [PATCH 45/85] Update baselines with new index signature rules --- tests/baselines/reference/objectSpread.js | 7 +- .../baselines/reference/objectSpread.symbols | 239 +++++++++--------- tests/baselines/reference/objectSpread.types | 7 +- .../objectSpreadIndexSignature.errors.txt | 35 +++ .../reference/objectSpreadIndexSignature.js | 2 + .../objectSpreadIndexSignature.symbols | 83 ------ .../objectSpreadIndexSignature.types | 91 ------- .../reference/objectSpreadIntersection.types | 8 +- .../reference/objectSpreadNegative.errors.txt | 8 +- .../reference/objectSpreadUnion.types | 8 +- .../conformance/types/spread/objectSpread.ts | 4 +- .../spread/objectSpreadIndexSignature.ts | 1 + 12 files changed, 175 insertions(+), 318 deletions(-) create mode 100644 tests/baselines/reference/objectSpreadIndexSignature.errors.txt delete mode 100644 tests/baselines/reference/objectSpreadIndexSignature.symbols delete mode 100644 tests/baselines/reference/objectSpreadIndexSignature.types diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 359284f9c6c51..23729d4cd6f21 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -35,14 +35,12 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null, undefined, functions and primitives besides string result in { } +// null, undefined, functions and primitives result in { } let spreadNull = { ...null }; let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; let spreadBool = { ...false }; let spreadFunc = { ...(function () { }) }; - -// strings get a numeric indexer: [n: number]: string let spreadStr = { ...'foo' }; // methods are not enumerable @@ -130,13 +128,12 @@ var propertyNested = __assign({ a: __assign({}, o) }); var op = { get a() { return 6; } }; var getter = __assign({}, op, { c: 7 }); getter.a = 12; -// null, undefined, functions and primitives besides string result in { } +// null, undefined, functions and primitives result in { } var spreadNull = __assign({}, null); var spreadUndefind = __assign({}, undefined); var spreadNum = __assign({}, 12); var spreadBool = __assign({}, false); var spreadFunc = __assign({}, (function () { })); -// strings get a numeric indexer: [n: number]: string var spreadStr = __assign({}, 'foo'); // methods are not enumerable var C = (function () { diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index fb7a1e22b33f3..039be9e0d7df5 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -150,7 +150,7 @@ getter.a = 12; >getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) >a : Symbol(a, Decl(objectSpread.ts, 32, 13)) -// null, undefined, functions and primitives besides string result in { } +// null, undefined, functions and primitives result in { } let spreadNull = { ...null }; >spreadNull : Symbol(spreadNull, Decl(objectSpread.ts, 37, 3)) @@ -166,209 +166,208 @@ let spreadBool = { ...false }; let spreadFunc = { ...(function () { }) }; >spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 41, 3)) -// strings get a numeric indexer: [n: number]: string let spreadStr = { ...'foo' }; ->spreadStr : Symbol(spreadStr, Decl(objectSpread.ts, 44, 3)) +>spreadStr : Symbol(spreadStr, Decl(objectSpread.ts, 42, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 44, 29)) ->p : Symbol(C.p, Decl(objectSpread.ts, 47, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 47, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 29)) +>p : Symbol(C.p, Decl(objectSpread.ts, 45, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 45, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 48, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 44, 29)) ->C : Symbol(C, Decl(objectSpread.ts, 44, 29)) +>c : Symbol(c, Decl(objectSpread.ts, 46, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 29)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 29)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 49, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 49, 14)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 47, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 47, 14)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 52, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 52, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) ->plus : Symbol(plus, Decl(objectSpread.ts, 52, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 50, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) +>plus : Symbol(plus, Decl(objectSpread.ts, 50, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 52, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 52, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 56, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 56, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 56, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 54, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 54, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 54, 33)) { ...o, a: 'wrong type?' } ->a : Symbol(a, Decl(objectSpread.ts, 57, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 55, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 58, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 58, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 58, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 56, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 56, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 56, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 59, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 57, 5)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 60, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 60, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 60, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 58, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 58, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 58, 32)) { ...o, ...swap }; // optional let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 64, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 64, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 62, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 62, 22)) let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 65, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 63, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 66, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 66, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 64, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 67, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 67, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 65, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 68, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 68, 25)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 66, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 66, 25)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 69, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 69, 30)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 67, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 67, 30)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 70, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 70, 18)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 68, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 68, 18)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 73, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 73, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 73, 31)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 71, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 71, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 71, 31)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 74, 5)) ->b : Symbol(b, Decl(objectSpread.ts, 74, 38)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 72, 5)) +>b : Symbol(b, Decl(objectSpread.ts, 72, 38)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 75, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 75, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 75, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 75, 43)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 73, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 73, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 73, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 73, 43)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 76, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 76, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 74, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 74, 34)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 77, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 77, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 77, 31)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 75, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 75, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 75, 31)) { ...o, b: 'yeah', ['at the end']: 14 } ->b : Symbol(b, Decl(objectSpread.ts, 78, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 78, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 76, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 76, 22)) // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 80, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 78, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 81, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 81, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 81, 29)) ->a : Symbol(a, Decl(objectSpread.ts, 81, 51)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 79, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 79, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 79, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 79, 51)) // generics function f(t: T, u: U): { ...T, ...U, id: string } { ->f : Symbol(f, Decl(objectSpread.ts, 81, 55)) ->T : Symbol(T, Decl(objectSpread.ts, 84, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 84, 13)) ->t : Symbol(t, Decl(objectSpread.ts, 84, 17)) ->T : Symbol(T, Decl(objectSpread.ts, 84, 11)) ->u : Symbol(u, Decl(objectSpread.ts, 84, 22)) ->U : Symbol(U, Decl(objectSpread.ts, 84, 13)) ->T : Symbol(T, Decl(objectSpread.ts, 84, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 84, 13)) ->id : Symbol(id, Decl(objectSpread.ts, 84, 43)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>T : Symbol(T, Decl(objectSpread.ts, 82, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 82, 13)) +>t : Symbol(t, Decl(objectSpread.ts, 82, 17)) +>T : Symbol(T, Decl(objectSpread.ts, 82, 11)) +>u : Symbol(u, Decl(objectSpread.ts, 82, 22)) +>U : Symbol(U, Decl(objectSpread.ts, 82, 13)) +>T : Symbol(T, Decl(objectSpread.ts, 82, 11)) +>U : Symbol(U, Decl(objectSpread.ts, 82, 13)) +>id : Symbol(id, Decl(objectSpread.ts, 82, 43)) return { ...t, ...u, id: 'id' }; ->id : Symbol(id, Decl(objectSpread.ts, 85, 24)) +>id : Symbol(id, Decl(objectSpread.ts, 83, 24)) } let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : Symbol(exclusive, Decl(objectSpread.ts, 87, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 87, 16)) ->a : Symbol(a, Decl(objectSpread.ts, 87, 28)) ->b : Symbol(b, Decl(objectSpread.ts, 87, 39)) ->c : Symbol(c, Decl(objectSpread.ts, 87, 50)) ->d : Symbol(d, Decl(objectSpread.ts, 87, 61)) +>exclusive : Symbol(exclusive, Decl(objectSpread.ts, 85, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 85, 16)) +>a : Symbol(a, Decl(objectSpread.ts, 85, 28)) +>b : Symbol(b, Decl(objectSpread.ts, 85, 39)) +>c : Symbol(c, Decl(objectSpread.ts, 85, 50)) +>d : Symbol(d, Decl(objectSpread.ts, 85, 61)) f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f : Symbol(f, Decl(objectSpread.ts, 81, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 7)) ->b : Symbol(b, Decl(objectSpread.ts, 88, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 88, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 88, 36)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 86, 7)) +>b : Symbol(b, Decl(objectSpread.ts, 86, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 86, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 86, 36)) let overlap: { id: string, a: number, b: string } = ->overlap : Symbol(overlap, Decl(objectSpread.ts, 89, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 89, 14)) ->a : Symbol(a, Decl(objectSpread.ts, 89, 26)) ->b : Symbol(b, Decl(objectSpread.ts, 89, 37)) +>overlap : Symbol(overlap, Decl(objectSpread.ts, 87, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 87, 14)) +>a : Symbol(a, Decl(objectSpread.ts, 87, 26)) +>b : Symbol(b, Decl(objectSpread.ts, 87, 37)) f({ a: 1 }, { a: 2, b: 'extra' }) ->f : Symbol(f, Decl(objectSpread.ts, 81, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 17)) ->b : Symbol(b, Decl(objectSpread.ts, 90, 23)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 88, 17)) +>b : Symbol(b, Decl(objectSpread.ts, 88, 23)) let overlapConflict: { id:string, a: string } = ->overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 91, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 91, 22)) ->a : Symbol(a, Decl(objectSpread.ts, 91, 33)) +>overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 89, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 89, 22)) +>a : Symbol(a, Decl(objectSpread.ts, 89, 33)) f({ a: 1 }, { a: 'mismatch' }) ->f : Symbol(f, Decl(objectSpread.ts, 81, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 92, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 92, 17)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 7)) +>a : Symbol(a, Decl(objectSpread.ts, 90, 17)) let overwriteId: { id: string, a: number, c: number, d: string } = ->overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 93, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 93, 18)) ->a : Symbol(a, Decl(objectSpread.ts, 93, 30)) ->c : Symbol(c, Decl(objectSpread.ts, 93, 41)) ->d : Symbol(d, Decl(objectSpread.ts, 93, 52)) +>overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 91, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 91, 18)) +>a : Symbol(a, Decl(objectSpread.ts, 91, 30)) +>c : Symbol(c, Decl(objectSpread.ts, 91, 41)) +>d : Symbol(d, Decl(objectSpread.ts, 91, 52)) f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f : Symbol(f, Decl(objectSpread.ts, 81, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 94, 7)) ->id : Symbol(id, Decl(objectSpread.ts, 94, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 94, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 94, 33)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>a : Symbol(a, Decl(objectSpread.ts, 92, 7)) +>id : Symbol(id, Decl(objectSpread.ts, 92, 13)) +>c : Symbol(c, Decl(objectSpread.ts, 92, 27)) +>d : Symbol(d, Decl(objectSpread.ts, 92, 33)) class D { m() { }; q = 2; } ->D : Symbol(D, Decl(objectSpread.ts, 94, 44)) ->m : Symbol(D.m, Decl(objectSpread.ts, 96, 9)) ->q : Symbol(D.q, Decl(objectSpread.ts, 96, 18)) +>D : Symbol(D, Decl(objectSpread.ts, 92, 44)) +>m : Symbol(D.m, Decl(objectSpread.ts, 94, 9)) +>q : Symbol(D.q, Decl(objectSpread.ts, 94, 18)) let classesAreWrong: { id: string, ...C, ...D } = ->classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 97, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 97, 22)) ->C : Symbol(C, Decl(objectSpread.ts, 44, 29)) ->D : Symbol(D, Decl(objectSpread.ts, 94, 44)) +>classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 95, 3)) +>id : Symbol(id, Decl(objectSpread.ts, 95, 22)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 29)) +>D : Symbol(D, Decl(objectSpread.ts, 92, 44)) f(new C(), new D()) ->f : Symbol(f, Decl(objectSpread.ts, 81, 55)) ->C : Symbol(C, Decl(objectSpread.ts, 44, 29)) ->D : Symbol(D, Decl(objectSpread.ts, 94, 44)) +>f : Symbol(f, Decl(objectSpread.ts, 79, 55)) +>C : Symbol(C, Decl(objectSpread.ts, 42, 29)) +>D : Symbol(D, Decl(objectSpread.ts, 92, 44)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index b6fcb9150bf3a..78f4f7583d939 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -223,7 +223,7 @@ getter.a = 12; >a : number >12 : 12 -// null, undefined, functions and primitives besides string result in { } +// null, undefined, functions and primitives result in { } let spreadNull = { ...null }; >spreadNull : {} >{ ...null } : {} @@ -249,10 +249,9 @@ let spreadFunc = { ...(function () { }) }; >(function () { }) : () => void >function () { } : () => void -// strings get a numeric indexer: [n: number]: string let spreadStr = { ...'foo' }; ->spreadStr : { [x: number]: string; } ->{ ...'foo' } : { [x: number]: string; } +>spreadStr : {} +>{ ...'foo' } : {} // methods are not enumerable class C { p = 1; m() { } } diff --git a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt new file mode 100644 index 0000000000000..3909c46695291 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt @@ -0,0 +1,35 @@ +tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,39): error TS2698: Type literals with spreads cannot contain an index signature. +tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(24,20): error TS2698: Type literals with spreads cannot contain an index signature. + + +==== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts (2 errors) ==== + class C { + a: number; + c: boolean; + } + // index signatures are not allowed in object literals with spread types + let c: { ...C, b: string, c?: string, [n: number]: string }; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Type literals with spreads cannot contain an index signature. + let n: number = c.a; + let s: string = c[12]; + interface Indexed { + [n: string]: number; + a: number; + } + let i: { ...Indexed, b: number }; + n = i[101]; + n = i.b; + interface Indexed2 { + [n: string]: boolean; + c: boolean; + } + let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; + let nb: number | boolean = ii[1001]; + + function f(t: T) { + let i: { ...T, [n: number]: string }; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Type literals with spreads cannot contain an index signature. + } + \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js index 709cd9446d8da..ab18c0f24a942 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.js +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -3,6 +3,7 @@ class C { a: number; c: boolean; } +// index signatures are not allowed in object literals with spread types let c: { ...C, b: string, c?: string, [n: number]: string }; let n: number = c.a; let s: string = c[12]; @@ -31,6 +32,7 @@ var C = (function () { } return C; }()); +// index signatures are not allowed in object literals with spread types var c; var n = c.a; var s = c[12]; diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols deleted file mode 100644 index e76ad3e1b1362..0000000000000 --- a/tests/baselines/reference/objectSpreadIndexSignature.symbols +++ /dev/null @@ -1,83 +0,0 @@ -=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === -class C { ->C : Symbol(C, Decl(objectSpreadIndexSignature.ts, 0, 0)) - - a: number; ->a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) - - c: boolean; ->c : Symbol(C.c, Decl(objectSpreadIndexSignature.ts, 1, 14)) -} -let c: { ...C, b: string, c?: string, [n: number]: string }; ->c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 3)) ->C : Symbol(C, Decl(objectSpreadIndexSignature.ts, 0, 0)) ->b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 4, 14)) ->c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 25)) ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 4, 39)) - -let n: number = c.a; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 3)) ->c.a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) ->c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 3)) ->a : Symbol(C.a, Decl(objectSpreadIndexSignature.ts, 0, 9)) - -let s: string = c[12]; ->s : Symbol(s, Decl(objectSpreadIndexSignature.ts, 6, 3)) ->c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 4, 3)) - -interface Indexed { ->Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) - - [n: string]: number; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 8, 5)) - - a: number; ->a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 8, 24)) -} -let i: { ...Indexed, b: number }; ->i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) ->Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) ->b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) - -n = i[101]; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 3)) ->i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) - -n = i.b; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 3)) ->i.b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) ->i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 11, 3)) ->b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 11, 20)) - -interface Indexed2 { ->Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 13, 8)) - - [n: string]: boolean; ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 15, 5)) - - c: boolean; ->c : Symbol(Indexed2.c, Decl(objectSpreadIndexSignature.ts, 15, 25)) -} -let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; ->ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 18, 3)) ->Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 6, 22)) ->Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 13, 8)) ->b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 18, 34)) ->d : Symbol(d, Decl(objectSpreadIndexSignature.ts, 18, 46)) - -let nb: number | boolean = ii[1001]; ->nb : Symbol(nb, Decl(objectSpreadIndexSignature.ts, 19, 3)) ->ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 18, 3)) - -function f(t: T) { ->f : Symbol(f, Decl(objectSpreadIndexSignature.ts, 19, 36)) ->T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 21, 11)) ->t : Symbol(t, Decl(objectSpreadIndexSignature.ts, 21, 14)) ->T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 21, 11)) - - let i: { ...T, [n: number]: string }; ->i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 22, 7)) ->T : Symbol(T, Decl(objectSpreadIndexSignature.ts, 21, 11)) ->n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 22, 20)) -} - diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types deleted file mode 100644 index f646361765d4b..0000000000000 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ /dev/null @@ -1,91 +0,0 @@ -=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === -class C { ->C : C - - a: number; ->a : number - - c: boolean; ->c : boolean -} -let c: { ...C, b: string, c?: string, [n: number]: string }; ->c : { [x: number]: string; b: string; c: string | boolean; a: number; } ->C : C ->b : string ->c : string ->n : number - -let n: number = c.a; ->n : number ->c.a : number ->c : { [x: number]: string; b: string; c: string | boolean; a: number; } ->a : number - -let s: string = c[12]; ->s : string ->c[12] : string ->c : { [x: number]: string; b: string; c: string | boolean; a: number; } ->12 : 12 - -interface Indexed { ->Indexed : Indexed - - [n: string]: number; ->n : string - - a: number; ->a : number -} -let i: { ...Indexed, b: number }; ->i : { [n: string]: number; b: number; a: number; } ->Indexed : Indexed ->b : number - -n = i[101]; ->n = i[101] : number ->n : number ->i[101] : number ->i : { [n: string]: number; b: number; a: number; } ->101 : 101 - -n = i.b; ->n = i.b : number ->n : number ->i.b : number ->i : { [n: string]: number; b: number; a: number; } ->b : number - -interface Indexed2 { ->Indexed2 : Indexed2 - - [n: string]: boolean; ->n : string - - c: boolean; ->c : boolean -} -let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; ->ii : { [x: string]: number | boolean; b: boolean; d: number; c: boolean; a: number; } ->Indexed : Indexed ->Indexed2 : Indexed2 ->b : boolean ->d : number - -let nb: number | boolean = ii[1001]; ->nb : number | boolean ->ii[1001] : number | boolean ->ii : { [x: string]: number | boolean; b: boolean; d: number; c: boolean; a: number; } ->1001 : 1001 - -function f(t: T) { ->f : (t: T) => void ->T : T ->t : T ->T : T - - let i: { ...T, [n: number]: string }; ->i : { ...T; [n: number]: string; } ->T : T ->n : number -} - diff --git a/tests/baselines/reference/objectSpreadIntersection.types b/tests/baselines/reference/objectSpreadIntersection.types index 13c1384698f08..e6a7b7c19ee7f 100644 --- a/tests/baselines/reference/objectSpreadIntersection.types +++ b/tests/baselines/reference/objectSpreadIntersection.types @@ -187,21 +187,21 @@ function iteratedIntersectionUnion(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'qux' }; ->result : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } ->{ ...tu, ...uv, id: 'qux' } : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } +>result : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } +>{ ...tu, ...uv, id: 'qux' } : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } >tu : any >uv : any >id : string >'qux' : "qux" let assignable: { ...(T & U), ...(U | V), id: string } = result; ->assignable : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } +>assignable : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } >T : T >U : U >U : U >V : V >id : string ->result : { ...T & U; ...T & U; ...U; id: string; } | { ...T & U; ...T & U; ...V; id: string; } +>result : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; } } diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 64928782280ae..16c257b104419 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -11,8 +11,8 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(30,12): error TS233 tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,17): error TS2339: Property 'undefined' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,11): error TS2339: Property 'toFixed' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,11): error TS2339: Property 'toFixed' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,11): error TS2339: Property 'length' does not exist on type '{ [x: number]: string; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS2339: Property 'charAt' does not exist on type '{ [x: number]: string; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,11): error TS2339: Property 'length' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS2339: Property 'charAt' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(55,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. @@ -87,10 +87,10 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS232 let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' ~~~~~~ -!!! error TS2339: Property 'length' does not exist on type '{ [x: number]: string; }'. +!!! error TS2339: Property 'length' does not exist on type '{}'. spreadStr.charAt(1); // error, no methods either ~~~~~~ -!!! error TS2339: Property 'charAt' does not exist on type '{ [x: number]: string; }'. +!!! error TS2339: Property 'charAt' does not exist on type '{}'. let spreadBool = { ...true }; spreadBool.valueOf(); // error, what were you thinking? let spreadFunc = { ...function () { } } diff --git a/tests/baselines/reference/objectSpreadUnion.types b/tests/baselines/reference/objectSpreadUnion.types index 5d8cdbae24a70..20633295acba3 100644 --- a/tests/baselines/reference/objectSpreadUnion.types +++ b/tests/baselines/reference/objectSpreadUnion.types @@ -96,8 +96,8 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >V : V let result = { ...tu, ...uv, id: 'bar' }; ->result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } ->{ ...tu, ...uv, id: 'bar' } : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } +>result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } +>{ ...tu, ...uv, id: 'bar' } : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } >tu : any >uv : any >id : string @@ -118,13 +118,13 @@ function iteratedDoubleUnion(t: T, u: U, v: V): void { >id : string let assignable: { ...(T | U), ...(U | V), id: string } = result; ->assignable : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } +>assignable : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } >T : T >U : U >U : U >V : V >id : string ->result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...U; ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...T; ...V; id: string; } | { ...U; ...V; id: string; } | { ...T; ...U; ...V; id: string; } +>result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; } } diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index e35a84956c00a..daadb1e3270e5 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -35,14 +35,12 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null, undefined, functions and primitives besides string result in { } +// null, undefined, functions and primitives result in { } let spreadNull = { ...null }; let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; let spreadBool = { ...false }; let spreadFunc = { ...(function () { }) }; - -// strings get a numeric indexer: [n: number]: string let spreadStr = { ...'foo' }; // methods are not enumerable diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts index daf8e4e63c573..8c9194d2d4cdc 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -2,6 +2,7 @@ class C { a: number; c: boolean; } +// index signatures are not allowed in object literals with spread types let c: { ...C, b: string, c?: string, [n: number]: string }; let n: number = c.a; let s: string = c[12]; From 510ab1c42ff4652f7209efa69846b6c8fc75fb42 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 21 Oct 2016 16:33:28 -0700 Subject: [PATCH 46/85] Move n-ary spread handling into separate function. To be moved to callers in the next step. --- src/compiler/checker.ts | 63 ++++++++++++++++++---------- src/compiler/diagnosticMessages.json | 4 ++ 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9df086f1bb70f..abc70d49a435b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5803,7 +5803,8 @@ namespace ts { return getSpreadType(spreads, node.symbol, aliasSymbol, aliasTypeArguments); } - function getSpreadType(types: Type[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getSpreadType(types: Type[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]) { + // TODO: Move this function's body into callers, except for caching, and leave that back in getSpreadType proper if (types.length === 0) { return emptyObjectType; } @@ -5811,9 +5812,18 @@ namespace ts { if (id in spreadTypes) { return spreadTypes[id]; } - let right = types.pop(); - if (right.flags & TypeFlags.StringLike) { - right = createAnonymousType(symbol, emptySymbols, emptyArray, emptyArray, undefined, createIndexInfo(stringType, /*isReadonly*/ false)); + let spread: Type = emptyObjectType; + for (const left of types) { + spread = getSpreadTypeWorker(spread, left, symbol, aliasSymbol, aliasTypeArguments); + } + return spread; + } + + function getSpreadTypeWorker(left: Type, right: Type, symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + // TODO: Reorder everything now that it's order independent, to be easier to read + const id = getTypeListId([left, right]); + if (id in spreadTypes) { + return spreadTypes[id]; } if (right.flags & TypeFlags.Any) { return anyType; @@ -5822,23 +5832,21 @@ namespace ts { // spread is right associative and associativity applies, so transform // (T ... U) ... V to T ... (U ... V) const rspread = right as SpreadType; - if (rspread.left !== emptyObjectType) { - types.push(rspread.left); + if (rspread.left === emptyObjectType) { + return getSpreadTypeWorker(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments); } - types.push(rspread.right); - return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); + return getSpreadTypeWorker(getSpreadTypeWorker(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments), + rspread.right, symbol, aliasSymbol, aliasTypeArguments); } if (right.flags & TypeFlags.Intersection) { right = resolveObjectIntersection(right as IntersectionType); } if (right.flags & TypeFlags.Union) { const spreads = map((right as UnionType).types, - t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); + t => getSpreadTypeWorker(left, t, symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } - const atBeginning = types.length === 0; - let left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); - if (right.flags & (TypeFlags.Primitive & ~TypeFlags.StringLike) || left.flags & TypeFlags.Any) { + if (right.flags & TypeFlags.Primitive || left.flags & TypeFlags.Any) { return left; } if (right.flags & TypeFlags.TypeParameter && @@ -5861,19 +5869,21 @@ namespace ts { } if (left.flags & TypeFlags.Union) { const spreads = map((left as UnionType).types, - t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); + t => getSpreadTypeWorker(t, right, symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } if (right.flags & TypeFlags.ObjectType && left.flags & TypeFlags.ObjectType) { const members = createMap(); const skippedPrivateMembers = createMap(); - let stringIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); - let numberIndexInfo = unionIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); - if (atBeginning) { - // only get index info from the entire type once per spread type - stringIndexInfo = unionIndexInfos(stringIndexInfo, getIndexInfoOfSymbol(symbol, IndexKind.String)); - numberIndexInfo = unionIndexInfos(numberIndexInfo, getIndexInfoOfSymbol(symbol, IndexKind.Number)); - } + + // TODO: This is pretty ugly + const leftString = getIndexInfoOfType(left, IndexKind.String); + const rightString = getIndexInfoOfType(right, IndexKind.String); + const leftNumber = getIndexInfoOfType(left, IndexKind.Number); + const rightNumber = getIndexInfoOfType(right, IndexKind.Number); + const stringIndexInfo = leftString && rightString && unionIndexInfos(leftString, rightString); + const numberIndexInfo = leftNumber && rightNumber && unionIndexInfos(leftNumber, rightNumber); + const isFromSpread = right.symbol !== symbol; for (const rightProp of getPropertiesOfType(right)) { if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { @@ -5924,7 +5934,7 @@ namespace ts { } function resolveObjectIntersection(intersection: IntersectionType): IntersectionType | ResolvedType { - if (find(intersection.types, t => !(t.flags & TypeFlags.ObjectType) || couldContainTypeParameters(t))) { + if (find(intersection.types, t => !(t.flags & TypeFlags.ObjectType))) { return intersection; } const properties = getPropertiesOfType(intersection); @@ -15267,6 +15277,17 @@ namespace ts { checkTypeForDuplicateIndexSignatures(node); checkObjectTypeForDuplicateDeclarations(node); } + if (type.flags & (TypeFlags.ObjectType | TypeFlags.Spread) && + find(node.members, p => p.kind === SyntaxKind.SpreadTypeElement)) { + const declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.Number); + const declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.String); + if (declaredStringIndexer) { + error(declaredStringIndexer, Diagnostics.Type_literals_with_spreads_cannot_contain_an_index_signature); + } + if (declaredNumberIndexer) { + error(declaredNumberIndexer, Diagnostics.Type_literals_with_spreads_cannot_contain_an_index_signature); + } + } } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index bfc6dabfb9d1d..424d6f59ca0a0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1971,6 +1971,10 @@ "category": "Error", "code": 2697 }, + "Type literals with spreads cannot contain an index signature.": { + "category": "Error", + "code": 2698 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", From 485e2490e77c2aad766375e3981360bbe4fc9c4e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Sat, 22 Oct 2016 09:07:48 -0700 Subject: [PATCH 47/85] Move multiple-spread handling out of getSpreadType --- src/compiler/checker.ts | 50 +++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index abc70d49a435b..a610dcf2f36e9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5753,19 +5753,19 @@ namespace ts { } function getTypeFromSpreadTypeLiteral(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + let spread: Type = emptyObjectType; let members: Map; let stringIndexInfo: IndexInfo; let numberIndexInfo: IndexInfo; - const spreads: Type[] = []; for (const member of (node as TypeLiteralNode).members) { if (member.kind === SyntaxKind.SpreadTypeElement) { if (members) { - spreads.push(createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); + spread = getSpreadTypeWorker(spread, createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo), node.symbol, aliasSymbol, aliasTypeArguments); members = undefined; stringIndexInfo = undefined; numberIndexInfo = undefined; } - spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type)); + spread = getSpreadTypeWorker(spread, getTypeFromTypeNode((member as SpreadTypeElement).type), node.symbol, aliasSymbol, aliasTypeArguments); } else if (member.kind === SyntaxKind.IndexSignature) { const index = member as IndexSignatureDeclaration; @@ -5798,23 +5798,7 @@ namespace ts { } } if (members || stringIndexInfo || numberIndexInfo) { - spreads.push(createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo)); - } - return getSpreadType(spreads, node.symbol, aliasSymbol, aliasTypeArguments); - } - - function getSpreadType(types: Type[], symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]) { - // TODO: Move this function's body into callers, except for caching, and leave that back in getSpreadType proper - if (types.length === 0) { - return emptyObjectType; - } - const id = getTypeListId(types); - if (id in spreadTypes) { - return spreadTypes[id]; - } - let spread: Type = emptyObjectType; - for (const left of types) { - spread = getSpreadTypeWorker(spread, left, symbol, aliasSymbol, aliasTypeArguments); + spread = getSpreadTypeWorker(spread, createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo), node.symbol, aliasSymbol, aliasTypeArguments); } return spread; } @@ -5861,8 +5845,8 @@ namespace ts { left.flags & TypeFlags.Spread && (left as SpreadType).right.flags & TypeFlags.ObjectType) { // simplify two adjacent object types: T ... { x } ... { y } becomes T ... { x, y } - const simplified = getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments); - return getSpreadType([(left as SpreadType).left, simplified], symbol, aliasSymbol, aliasTypeArguments); + const simplified = getSpreadTypeWorker(right, (left as SpreadType).right, symbol, aliasSymbol, aliasTypeArguments); + return getSpreadTypeWorker((left as SpreadType).left, simplified, symbol, aliasSymbol, aliasTypeArguments); } if (left.flags & TypeFlags.Intersection) { left = resolveObjectIntersection(left as IntersectionType); @@ -6355,7 +6339,7 @@ namespace ts { } if (type.flags & TypeFlags.Spread) { const spread = type as SpreadType; - return getSpreadType([instantiateType(spread.left, mapper), instantiateType(spread.right, mapper)], type.symbol, type.aliasSymbol, mapper.targetTypes); + return getSpreadTypeWorker(instantiateType(spread.left, mapper), instantiateType(spread.right, mapper), type.symbol, type.aliasSymbol, mapper.targetTypes); } } return type; @@ -10881,7 +10865,9 @@ namespace ts { let propertiesTable = createMap(); let propertiesArray: Symbol[] = []; - const spreads: Type[] = []; + let spread: Type = emptyObjectType; + let propagatedFlags: TypeFlags = 0; + const contextualType = getApparentTypeOfContextualType(node); const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); @@ -10947,13 +10933,15 @@ namespace ts { } else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { if (propertiesArray.length > 0) { - spreads.push(createObjectLiteralType()); + spread = getSpreadTypeWorker(spread, createObjectLiteralType(), node.symbol); propertiesArray = []; propertiesTable = createMap(); hasComputedStringProperty = false; hasComputedNumberProperty = false; + typeFlags = 0; } - spreads.push(checkExpression((memberDecl as SpreadElementExpression).expression)); + const type = checkExpression((memberDecl as SpreadElementExpression).expression); + spread = getSpreadTypeWorker(spread, type, node.symbol); continue; } else { @@ -10995,12 +10983,11 @@ namespace ts { } } - if (spreads.length > 0) { + if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spreads.push(createObjectLiteralType()); + spread = getSpreadTypeWorker(spread, createObjectLiteralType(), node.symbol); } - const propagatedFlags = getPropagatingFlagsOfTypes(spreads, /*excludeKinds*/ TypeFlags.Nullable); - const spread = getSpreadType(spreads, node.symbol, undefined, undefined); + // TODO: REname getSpreadTypeWorker back to getSpreadType spread.flags |= propagatedFlags; return spread; } @@ -11019,6 +11006,9 @@ namespace ts { if (inDestructuringPattern) { result.pattern = node; } + if (!(result.flags & TypeFlags.Nullable)) { + propagatedFlags |= (result.flags & TypeFlags.PropagatingFlags); + } return result; } } From 16dfdc49dc25d11a51a60225b5aee63ef890b8ca Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Sat, 22 Oct 2016 10:08:58 -0700 Subject: [PATCH 48/85] Clean up and reorder getSpreadType body --- src/compiler/checker.ts | 93 +++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a610dcf2f36e9..2560b12597d64 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4358,8 +4358,8 @@ namespace ts { getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly); } - function unionIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo { - return !info1 ? info2 : !info2 ? info1 : createIndexInfo( + function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo { + return info1 && info2 && createIndexInfo( getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); } @@ -5760,12 +5760,14 @@ namespace ts { for (const member of (node as TypeLiteralNode).members) { if (member.kind === SyntaxKind.SpreadTypeElement) { if (members) { - spread = getSpreadTypeWorker(spread, createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo), node.symbol, aliasSymbol, aliasTypeArguments); + const type = createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); members = undefined; stringIndexInfo = undefined; numberIndexInfo = undefined; } - spread = getSpreadTypeWorker(spread, getTypeFromTypeNode((member as SpreadTypeElement).type), node.symbol, aliasSymbol, aliasTypeArguments); + const type = getTypeFromTypeNode((member as SpreadTypeElement).type); + spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); } else if (member.kind === SyntaxKind.IndexSignature) { const index = member as IndexSignatureDeclaration; @@ -5798,75 +5800,77 @@ namespace ts { } } if (members || stringIndexInfo || numberIndexInfo) { - spread = getSpreadTypeWorker(spread, createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo), node.symbol, aliasSymbol, aliasTypeArguments); + const type = createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); } return spread; } - function getSpreadTypeWorker(left: Type, right: Type, symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { // TODO: Reorder everything now that it's order independent, to be easier to read const id = getTypeListId([left, right]); if (id in spreadTypes) { return spreadTypes[id]; } - if (right.flags & TypeFlags.Any) { + + // non-spreadable types + if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } - if (right.flags & TypeFlags.Spread) { - // spread is right associative and associativity applies, so transform - // (T ... U) ... V to T ... (U ... V) - const rspread = right as SpreadType; - if (rspread.left === emptyObjectType) { - return getSpreadTypeWorker(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments); - } - return getSpreadTypeWorker(getSpreadTypeWorker(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments), - rspread.right, symbol, aliasSymbol, aliasTypeArguments); + if (left.flags & TypeFlags.Intersection) { + left = resolveObjectIntersection(left as IntersectionType); } if (right.flags & TypeFlags.Intersection) { right = resolveObjectIntersection(right as IntersectionType); } + if (left.flags & TypeFlags.Union) { + const spreads = map((left as UnionType).types, + t => getSpreadType(t, right, symbol, aliasSymbol, aliasTypeArguments)); + return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); + } if (right.flags & TypeFlags.Union) { const spreads = map((right as UnionType).types, - t => getSpreadTypeWorker(left, t, symbol, aliasSymbol, aliasTypeArguments)); + t => getSpreadType(left, t, symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } - if (right.flags & TypeFlags.Primitive || left.flags & TypeFlags.Any) { + if (right.flags & TypeFlags.Primitive) { return left; } - if (right.flags & TypeFlags.TypeParameter && - left.flags & TypeFlags.Spread && + + // spread simplifications + if (left.flags & TypeFlags.Spread && + right.flags & TypeFlags.TypeParameter && (left as SpreadType).right.flags & TypeFlags.TypeParameter && right.symbol === (left as SpreadType).right.symbol) { // for types like T ... T, just return ... T return left; } - - if (right.flags & TypeFlags.ObjectType && - left.flags & TypeFlags.Spread && + if (left.flags & TypeFlags.Spread && + right.flags & TypeFlags.ObjectType && (left as SpreadType).right.flags & TypeFlags.ObjectType) { // simplify two adjacent object types: T ... { x } ... { y } becomes T ... { x, y } - const simplified = getSpreadTypeWorker(right, (left as SpreadType).right, symbol, aliasSymbol, aliasTypeArguments); - return getSpreadTypeWorker((left as SpreadType).left, simplified, symbol, aliasSymbol, aliasTypeArguments); - } - if (left.flags & TypeFlags.Intersection) { - left = resolveObjectIntersection(left as IntersectionType); + const simplified = getSpreadType(right, (left as SpreadType).right, symbol, aliasSymbol, aliasTypeArguments); + return getSpreadType((left as SpreadType).left, simplified, symbol, aliasSymbol, aliasTypeArguments); } - if (left.flags & TypeFlags.Union) { - const spreads = map((left as UnionType).types, - t => getSpreadTypeWorker(t, right, symbol, aliasSymbol, aliasTypeArguments)); - return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); + if (right.flags & TypeFlags.Spread) { + // spread is right associative and associativity applies, so transform + // (T ... U) ... V to T ... (U ... V) + const rspread = right as SpreadType; + if (rspread.left === emptyObjectType) { + // U ... ({} ... T) => (U ... T) + return getSpreadType(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments); + } + return getSpreadType(getSpreadType(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments), + rspread.right, symbol, aliasSymbol, aliasTypeArguments); } + + // create an object type if left and right are both objects, + // otherwise create a spread type if (right.flags & TypeFlags.ObjectType && left.flags & TypeFlags.ObjectType) { const members = createMap(); const skippedPrivateMembers = createMap(); - - // TODO: This is pretty ugly - const leftString = getIndexInfoOfType(left, IndexKind.String); - const rightString = getIndexInfoOfType(right, IndexKind.String); - const leftNumber = getIndexInfoOfType(left, IndexKind.Number); - const rightNumber = getIndexInfoOfType(right, IndexKind.Number); - const stringIndexInfo = leftString && rightString && unionIndexInfos(leftString, rightString); - const numberIndexInfo = leftNumber && rightNumber && unionIndexInfos(leftNumber, rightNumber); + const stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); + const numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); const isFromSpread = right.symbol !== symbol; for (const rightProp of getPropertiesOfType(right)) { @@ -6339,7 +6343,7 @@ namespace ts { } if (type.flags & TypeFlags.Spread) { const spread = type as SpreadType; - return getSpreadTypeWorker(instantiateType(spread.left, mapper), instantiateType(spread.right, mapper), type.symbol, type.aliasSymbol, mapper.targetTypes); + return getSpreadType(instantiateType(spread.left, mapper), instantiateType(spread.right, mapper), type.symbol, type.aliasSymbol, mapper.targetTypes); } } return type; @@ -10933,7 +10937,7 @@ namespace ts { } else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { if (propertiesArray.length > 0) { - spread = getSpreadTypeWorker(spread, createObjectLiteralType(), node.symbol); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol); propertiesArray = []; propertiesTable = createMap(); hasComputedStringProperty = false; @@ -10941,7 +10945,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadElementExpression).expression); - spread = getSpreadTypeWorker(spread, type, node.symbol); + spread = getSpreadType(spread, type, node.symbol); continue; } else { @@ -10985,9 +10989,8 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadTypeWorker(spread, createObjectLiteralType(), node.symbol); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol); } - // TODO: REname getSpreadTypeWorker back to getSpreadType spread.flags |= propagatedFlags; return spread; } From 66d4798145ae9b7af5633b64f228f149e10a4fee Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 24 Oct 2016 09:21:23 -0700 Subject: [PATCH 49/85] Error for call/construct signatures in spread type 1. Simplify the error reporting code to handle all kinds of signatures. 2. Remove index signature handling code when creating a spread type since it's an error anyway. --- src/compiler/checker.ts | 36 +++++++--------------------- src/compiler/diagnosticMessages.json | 2 +- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2560b12597d64..e19c779b35a84 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5769,24 +5769,10 @@ namespace ts { const type = getTypeFromTypeNode((member as SpreadTypeElement).type); spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); } - else if (member.kind === SyntaxKind.IndexSignature) { - const index = member as IndexSignatureDeclaration; - if (index.parameters.length === 1) { - const parameter = index.parameters[0]; - if (parameter && parameter.type) { - const indexInfo = createIndexInfo(index.type ? getTypeFromTypeNode(index.type) : anyType, - (getModifierFlags(index) & ModifierFlags.Readonly) !== 0, index); - if (parameter.type.kind === SyntaxKind.StringKeyword) { - stringIndexInfo = indexInfo; - } - else { - numberIndexInfo = indexInfo; - } - } - } - } - else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) { - // note that spread types don't include call and construct signatures + else if (member.kind !== SyntaxKind.IndexSignature && + member.kind !== SyntaxKind.CallSignature && + member.kind !== SyntaxKind.ConstructSignature) { + // it is an error for spread types to include index, call or construct signatures const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); const text = getTextOfPropertyName(member.name); const symbol = createSymbol(flags, text); @@ -15270,15 +15256,11 @@ namespace ts { checkTypeForDuplicateIndexSignatures(node); checkObjectTypeForDuplicateDeclarations(node); } - if (type.flags & (TypeFlags.ObjectType | TypeFlags.Spread) && - find(node.members, p => p.kind === SyntaxKind.SpreadTypeElement)) { - const declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.Number); - const declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.String); - if (declaredStringIndexer) { - error(declaredStringIndexer, Diagnostics.Type_literals_with_spreads_cannot_contain_an_index_signature); - } - if (declaredNumberIndexer) { - error(declaredNumberIndexer, Diagnostics.Type_literals_with_spreads_cannot_contain_an_index_signature); + if (find(node.members, p => p.kind === SyntaxKind.SpreadTypeElement)) { + for (const signature of filter(node.members, p => p.kind === SyntaxKind.IndexSignature || + p.kind === SyntaxKind.CallSignature || + p.kind === SyntaxKind.ConstructSignature)) { + error(signature, Diagnostics.Type_literals_with_spreads_cannot_contain_index_call_or_construct_signatures); } } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 424d6f59ca0a0..68206196dff18 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1971,7 +1971,7 @@ "category": "Error", "code": 2697 }, - "Type literals with spreads cannot contain an index signature.": { + "Type literals with spreads cannot contain index, call or construct signatures.": { "category": "Error", "code": 2698 }, From 24300932cfea12050748522f380bc53ee504f0b2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 24 Oct 2016 09:22:40 -0700 Subject: [PATCH 50/85] Update baselines with new spread type index errors --- .../reference/objectSpreadIndexSignature.errors.txt | 8 ++++---- tests/baselines/reference/objectSpreadNegative.errors.txt | 8 +++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt index 3909c46695291..fa4d4c28aecaf 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt +++ b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt @@ -1,5 +1,5 @@ -tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,39): error TS2698: Type literals with spreads cannot contain an index signature. -tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(24,20): error TS2698: Type literals with spreads cannot contain an index signature. +tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,39): error TS2698: Type literals with spreads cannot contain index, call or construct signatures. +tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(24,20): error TS2698: Type literals with spreads cannot contain index, call or construct signatures. ==== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts (2 errors) ==== @@ -10,7 +10,7 @@ tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(24,20): error // index signatures are not allowed in object literals with spread types let c: { ...C, b: string, c?: string, [n: number]: string }; ~~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Type literals with spreads cannot contain an index signature. +!!! error TS2698: Type literals with spreads cannot contain index, call or construct signatures. let n: number = c.a; let s: string = c[12]; interface Indexed { @@ -30,6 +30,6 @@ tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(24,20): error function f(t: T) { let i: { ...T, [n: number]: string }; ~~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Type literals with spreads cannot contain an index signature. +!!! error TS2698: Type literals with spreads cannot contain index, call or construct signatures. } \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 16c257b104419..90cd2405c24e0 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -16,13 +16,15 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS233 tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,12): error TS2339: Property 'b' does not exist on type '{}'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(55,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,48): error TS2698: Type literals with spreads cannot contain index, call or construct signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,69): error TS2698: Type literals with spreads cannot contain index, call or construct signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,9): error TS2322: Type '{ ...T & V }' is not assignable to type '{ ...T & U }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (19 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (21 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -113,6 +115,10 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS232 !!! error TS2339: Property 'm' does not exist on type '{ p: number; }'. let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Type literals with spreads cannot contain index, call or construct signatures. + ~~~~~~~~~~~~~~~ +!!! error TS2698: Type literals with spreads cannot contain index, call or construct signatures. callableConstructableSpread(12); // error, no call signature ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. From a94fb2f5a3103b26eda73b02b0cb6554d371212f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 24 Oct 2016 09:40:10 -0700 Subject: [PATCH 51/85] Explain writeSpreadType a little better --- src/compiler/checker.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e19c779b35a84..cfe33252d67b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2338,6 +2338,8 @@ namespace ts { inObjectTypeLiteral = saveInObjectTypeLiteral; } if (type.right.symbol === container) { + // if type.right was written as part of the spread type, don't surround with ...{ }. + // this gives { a: number, ... T } instead of { ...{ a: number }, ...T } const saveInObjectTypeLiteral = inObjectTypeLiteral; inObjectTypeLiteral = true; writeObjectLiteralType(resolveStructuredTypeMembers(type.right)); From 35be8c351cadbc0fcb63d7370316db7856c31331 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 24 Oct 2016 10:02:04 -0700 Subject: [PATCH 52/85] Add more commentary to getSpreadType --- src/compiler/checker.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cfe33252d67b8..2378c65f6c3ba 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5794,23 +5794,29 @@ namespace ts { return spread; } + /** + * Since the source of spread types are object literals and type literals, which are not binary, + * this function should be called in a left folding style, with left = previous result of getSpreadType + * and right = the new element to be spread. + */ function getSpreadType(left: Type, right: Type, symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { - // TODO: Reorder everything now that it's order independent, to be easier to read const id = getTypeListId([left, right]); if (id in spreadTypes) { return spreadTypes[id]; } - // non-spreadable types + // any spreads to any if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } + // flatten intersections to objects if all member types are objects if (left.flags & TypeFlags.Intersection) { left = resolveObjectIntersection(left as IntersectionType); } if (right.flags & TypeFlags.Intersection) { right = resolveObjectIntersection(right as IntersectionType); } + // distribute unions if (left.flags & TypeFlags.Union) { const spreads = map((left as UnionType).types, t => getSpreadType(t, right, symbol, aliasSymbol, aliasTypeArguments)); @@ -5821,7 +5827,14 @@ namespace ts { t => getSpreadType(left, t, symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } - if (right.flags & TypeFlags.Primitive) { + // skip primitives + if (left.flags & TypeFlags.Primitive && right.flags & TypeFlags.Primitive) { + return emptyObjectType; + } + else if (left.flags & TypeFlags.Primitive) { + return right; + } + else if (right.flags & TypeFlags.Primitive) { return left; } @@ -5845,7 +5858,7 @@ namespace ts { // (T ... U) ... V to T ... (U ... V) const rspread = right as SpreadType; if (rspread.left === emptyObjectType) { - // U ... ({} ... T) => (U ... T) + // ... U ... ({} ... T) => ... U ... T return getSpreadType(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments); } return getSpreadType(getSpreadType(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments), From 39b9163715fac6975c5691ae4d85afbc2eabcb62 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 27 Oct 2016 16:03:01 -0700 Subject: [PATCH 53/85] Rename Experimental transform to ESNext 1. Spread/rest are no longer experimental. 2. We need a place to put stage 3 ES features. --- Jakefile.js | 4 ++-- src/compiler/transformer.ts | 4 ++-- src/compiler/transformers/{experimental.ts => esnext.ts} | 2 +- src/compiler/tsconfig.json | 2 +- src/harness/tsconfig.json | 2 +- src/services/tsconfig.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename src/compiler/transformers/{experimental.ts => esnext.ts} (95%) diff --git a/Jakefile.js b/Jakefile.js index e6698474a22c3..85f5ef681e84d 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -71,7 +71,7 @@ var compilerSources = [ "transformers/destructuring.ts", "transformers/ts.ts", "transformers/jsx.ts", - "transformers/experimental.ts", + "transformers/esnext.ts", "transformers/es2017.ts", "transformers/es2016.ts", "transformers/es2015.ts", @@ -108,7 +108,7 @@ var servicesSources = [ "transformers/destructuring.ts", "transformers/ts.ts", "transformers/jsx.ts", - "transformers/experimental.ts", + "transformers/esnext.ts", "transformers/es2017.ts", "transformers/es2016.ts", "transformers/es2015.ts", diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 467d57a0983fe..069b1e46af56b 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -1,7 +1,7 @@ /// /// /// -/// +/// /// /// /// @@ -117,7 +117,7 @@ namespace ts { transformers.push(transformJsx); } - transformers.push(transformExperimental); + transformers.push(transformESNext); if (languageVersion < ScriptTarget.ES2017) { transformers.push(transformES2017); } diff --git a/src/compiler/transformers/experimental.ts b/src/compiler/transformers/esnext.ts similarity index 95% rename from src/compiler/transformers/experimental.ts rename to src/compiler/transformers/esnext.ts index 2ee623db43aed..58cf1a1c01aeb 100644 --- a/src/compiler/transformers/experimental.ts +++ b/src/compiler/transformers/esnext.ts @@ -3,7 +3,7 @@ /*@internal*/ namespace ts { - export function transformExperimental(context: TransformationContext) { + export function transformESNext(context: TransformationContext) { return transformSourceFile; function transformSourceFile(node: SourceFile) { diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index 3e9b6a765bdeb..bd70a0afb10ed 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -27,7 +27,7 @@ "visitor.ts", "transformers/ts.ts", "transformers/jsx.ts", - "transformers/experimental.ts", + "transformers/esnext.ts", "transformers/es2017.ts", "transformers/es2016.ts", "transformers/es2015.ts", diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 9b174236cbcdc..d3a814f26caf0 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -29,7 +29,7 @@ "../compiler/visitor.ts", "../compiler/transformers/ts.ts", "../compiler/transformers/jsx.ts", - "../compiler/transformers/experimental.ts", + "../compiler/transformers/esnext.ts", "../compiler/transformers/es2017.ts", "../compiler/transformers/es2016.ts", "../compiler/transformers/es2015.ts", diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 2b947d60cf247..9c3e068918d5e 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -28,7 +28,7 @@ "../compiler/visitor.ts", "../compiler/transformers/ts.ts", "../compiler/transformers/jsx.ts", - "../compiler/transformers/experimental.ts", + "../compiler/transformers/esnext.ts", "../compiler/transformers/es2017.ts", "../compiler/transformers/es2016.ts", "../compiler/transformers/es2015.ts", From 988bf1fc69fbcdbd06e07dd5d988f1d221ab73cf Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 28 Oct 2016 10:24:30 -0700 Subject: [PATCH 54/85] Rename TransformFlags.Experimental -> ESNext --- src/compiler/binder.ts | 4 ++-- src/compiler/transformers/esnext.ts | 4 ++-- src/compiler/types.ts | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 0b8f59a82ef71..35844095da46b 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3160,8 +3160,8 @@ namespace ts { if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { // If an ObjectLiteralExpression contains a spread element, then it - // is an ES experimental node. - transformFlags |= TransformFlags.AssertExperimental; + // is an ES next node. + transformFlags |= TransformFlags.AssertESNext; } break; diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 58cf1a1c01aeb..1a8ed7da5eb4a 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -11,10 +11,10 @@ namespace ts { } function visitor(node: Node): VisitResult { - if (node.transformFlags & TransformFlags.Experimental) { + if (node.transformFlags & TransformFlags.ESNext) { return visitorWorker(node); } - else if (node.transformFlags & TransformFlags.ContainsExperimental) { + else if (node.transformFlags & TransformFlags.ContainsESNext) { return visitEachChild(node, visitor, context); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c9a51a9622baf..e331ebc02f6fa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3463,8 +3463,8 @@ namespace ts { ContainsTypeScript = 1 << 1, Jsx = 1 << 2, ContainsJsx = 1 << 3, - Experimental = 1 << 4, - ContainsExperimental = 1 << 5, + ESNext = 1 << 4, + ContainsESNext = 1 << 5, ES2017 = 1 << 6, ContainsES2017 = 1 << 7, ES2016 = 1 << 8, @@ -3498,7 +3498,7 @@ namespace ts { // - Bitmasks that are used to assert facts about the syntax of a node and its subtree. AssertTypeScript = TypeScript | ContainsTypeScript, AssertJsx = Jsx | ContainsJsx, - AssertExperimental = Experimental | ContainsExperimental, + AssertESNext = ESNext | ContainsESNext, AssertES2017 = ES2017 | ContainsES2017, AssertES2016 = ES2016 | ContainsES2016, AssertES2015 = ES2015 | ContainsES2015, @@ -3508,7 +3508,7 @@ namespace ts { // Scope Exclusions // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. - NodeExcludes = TypeScript | Jsx | Experimental | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, + NodeExcludes = TypeScript | Jsx | ESNext | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion, From f2d739ffcfef63b738bf6d71eb9e9d8b552cb71b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 11:36:25 -0700 Subject: [PATCH 55/85] Spread types handle nested index [access] types Nested index [access] types are treated as assignable to themselves only, just like type parameters. --- src/compiler/checker.ts | 7 ++++--- src/compiler/types.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 53d38c1892ff8..5447e652f08fe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6097,10 +6097,10 @@ namespace ts { } const spread = spreadTypes[id] = createType(TypeFlags.Spread) as SpreadType; Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.Object)), "Left flags: " + left.flags.toString(2)); - Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.Intersection | TypeFlags.Object)), "Right flags: " + right.flags.toString(2)); + Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.Intersection | TypeFlags.Index | TypeFlags.IndexedAccess | TypeFlags.Object)), "Right flags: " + right.flags.toString(2)); spread.symbol = symbol; spread.left = left as SpreadType | ResolvedType; - spread.right = right as TypeParameter | IntersectionType | ResolvedType; + spread.right = right as TypeParameter | IntersectionType | IndexType | IndexedAccessType | ResolvedType; spread.aliasSymbol = aliasSymbol; spread.aliasTypeArguments = aliasTypeArguments; return spread; @@ -7173,7 +7173,8 @@ namespace ts { spreadTypeRelatedTo(source.right.flags & TypeFlags.Object ? source.left as SpreadType : source, target.right.flags & TypeFlags.Object ? target.left as SpreadType : target); } - // If both right sides are type parameters or intersections, then they must be identical for the spread types to be related. + // If both right sides are type parameters, intersections, index types or indexed access types, + // then they must be identical for the spread types to be related. // It also means that the left sides are either spread types or object types. // if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 73d1c6d1ed9e7..ba5e6b2db9971 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2852,7 +2852,7 @@ namespace ts { /* @internal */ export interface SpreadType extends Type { left: SpreadType | ResolvedType; - right: TypeParameter | IntersectionType | ResolvedType; + right: TypeParameter | IntersectionType | IndexType | IndexedAccessType | ResolvedType; } /* @internal */ From f65dd2101c33fc6e222e97757c892402c68fe99a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 11:37:52 -0700 Subject: [PATCH 56/85] Test index [access] types inside spread types --- .../reference/objectSpreadGeneric.errors.txt | 50 ++++++++++++++++++- .../reference/objectSpreadGeneric.js | 46 +++++++++++++++++ .../types/spread/objectSpreadGeneric.ts | 24 +++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/objectSpreadGeneric.errors.txt b/tests/baselines/reference/objectSpreadGeneric.errors.txt index 8b9c767f6de3d..f1e2b7e4828f5 100644 --- a/tests/baselines/reference/objectSpreadGeneric.errors.txt +++ b/tests/baselines/reference/objectSpreadGeneric.errors.txt @@ -14,9 +14,17 @@ tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322 tests/cases/conformance/types/spread/objectSpreadGeneric.ts(42,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. tests/cases/conformance/types/spread/objectSpreadGeneric.ts(46,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(57,5): error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...keyof T }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(58,5): error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...keyof U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(61,5): error TS2322: Type '{ ...K }' is not assignable to type '{ ...keyof T }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(62,5): error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...K }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(63,5): error TS2322: Type '{ ...J }' is not assignable to type '{ ...keyof U }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(64,5): error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...J }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(70,5): error TS2322: Type '{ ...U[J] }' is not assignable to type '{ ...T[K] }'. +tests/cases/conformance/types/spread/objectSpreadGeneric.ts(71,5): error TS2322: Type '{ ...T[K] }' is not assignable to type '{ ...U[J] }'. -==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (16 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (24 errors) ==== function f(t: T, u: U, v: V): void { let o: { ...T, ...U, ...V }; let uus: { ...U, ...U}; @@ -97,4 +105,44 @@ tests/cases/conformance/types/spread/objectSpreadGeneric.ts(46,11): error TS2322 !!! error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable } + + function indexAccessedTest(t: T, u: U, key1: K, key2: J) { + let k1: { ...keyof T }; + let k2: { ...keyof U }; + let k3: { ...K }; + let k4: { ...J }; + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + ~~ +!!! error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...keyof T }'. + k2 = k1; // error + ~~ +!!! error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...keyof U }'. + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + ~~ +!!! error TS2322: Type '{ ...K }' is not assignable to type '{ ...keyof T }'. + k3 = k1; // error + ~~ +!!! error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...K }'. + k2 = k4; // error + ~~ +!!! error TS2322: Type '{ ...J }' is not assignable to type '{ ...keyof U }'. + k4 = k2; // error + ~~ +!!! error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...J }'. + + let i1: { ...T[K] }; + let i2: { ...U[J] }; + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + ~~ +!!! error TS2322: Type '{ ...U[J] }' is not assignable to type '{ ...T[K] }'. + i2 = i1; // error + ~~ +!!! error TS2322: Type '{ ...T[K] }' is not assignable to type '{ ...U[J] }'. + } \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadGeneric.js b/tests/baselines/reference/objectSpreadGeneric.js index fa19e47df39e7..8e89ebeef6416 100644 --- a/tests/baselines/reference/objectSpreadGeneric.js +++ b/tests/baselines/reference/objectSpreadGeneric.js @@ -47,6 +47,30 @@ function f(t: T, u: U, v: V): void { const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable } + +function indexAccessedTest(t: T, u: U, key1: K, key2: J) { + let k1: { ...keyof T }; + let k2: { ...keyof U }; + let k3: { ...K }; + let k4: { ...J }; + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + k2 = k1; // error + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + k3 = k1; // error + k2 = k4; // error + k4 = k2; // error + + let i1: { ...T[K] }; + let i2: { ...U[J] }; + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + i2 = i1; // error +} //// [objectSpreadGeneric.js] @@ -93,3 +117,25 @@ function f(t, u, v) { var mismatchSecond = __assign({ first: '1' }, t, { ssssssssecond: '2' }, u, { third: '3' }); // error, not assignable var mismatchLast = __assign({ first: '1' }, t, { second: '2' }, u, { thirrrrrrrd: '3' }); // error, not assignable } +function indexAccessedTest(t, u, key1, key2) { + var k1; + var k2; + var k3; + var k4; + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + k2 = k1; // error + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + k3 = k1; // error + k2 = k4; // error + k4 = k2; // error + var i1; + var i2; + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + i2 = i1; // error +} diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts index 63e9f00aaae62..6f22358b7e25a 100644 --- a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts +++ b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts @@ -46,3 +46,27 @@ function f(t: T, u: U, v: V): void { const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable } + +function indexAccessedTest(t: T, u: U, key1: K, key2: J) { + let k1: { ...keyof T }; + let k2: { ...keyof U }; + let k3: { ...K }; + let k4: { ...J }; + k1 = k1; // ok + k2 = k2; // ok + k1 = k2; // error + k2 = k1; // error + k3 = k3; // ok + k4 = k4; // ok + k1 = k3; // error + k3 = k1; // error + k2 = k4; // error + k4 = k2; // error + + let i1: { ...T[K] }; + let i2: { ...U[J] }; + i1 = i1; // ok + i2 = i2; // ok + i1 = i2; // error + i2 = i1; // error +} From a7c18367cad6169428d1ed09bfcc8ce768d51035 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 14:55:24 -0700 Subject: [PATCH 57/85] Parse, bind and check rest elements --- src/compiler/binder.ts | 72 ++++++++++++++++---- src/compiler/checker.ts | 98 +++++++++++++++++----------- src/compiler/diagnosticMessages.json | 6 +- src/compiler/parser.ts | 11 +++- src/compiler/types.ts | 19 +++--- src/compiler/utilities.ts | 16 +++++ 6 files changed, 161 insertions(+), 61 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b0c456a677068..a4d9a5a30ed02 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1916,6 +1916,9 @@ namespace ts { return bindParameter(node); case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: + if ((node as BindingElement).dotDotDotToken && node.parent.kind === SyntaxKind.ObjectBindingPattern) { + emitFlags |= NodeFlags.HasRestAttribute; + } return bindVariableDeclarationOrBindingElement(node); case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -1931,7 +1934,11 @@ namespace ts { case SyntaxKind.SpreadElementExpression: case SyntaxKind.JsxSpreadAttribute: - emitFlags |= NodeFlags.HasSpreadAttribute; + let root = container; + while (root && root.kind !== SyntaxKind.BinaryExpression) { + root = root.parent; + } + emitFlags |= root && isDestructuringAssignment(root) ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute; return; case SyntaxKind.CallSignature: @@ -2542,10 +2549,13 @@ namespace ts { const operatorTokenKind = node.operatorToken.kind; const leftKind = node.left.kind; - if (operatorTokenKind === SyntaxKind.EqualsToken - && (leftKind === SyntaxKind.ObjectLiteralExpression - || leftKind === SyntaxKind.ArrayLiteralExpression)) { - // Destructuring assignments are ES6 syntax. + if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) { + // Destructuring object assignments with are ES2015 syntax + // and possibly ESNext if they contain rest + transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment; + } + else if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ArrayLiteralExpression) { + // Destructuring assignments are ES2015 syntax. transformFlags |= TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment; } else if (operatorTokenKind === SyntaxKind.AsteriskAsteriskToken @@ -2579,6 +2589,11 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments; } + // parameters with object rest destructuring are ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + // If a parameter has an initializer, a binding pattern or a dotDotDot token, then // it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel. if (subtreeFlags & TransformFlags.ContainsBindingPattern || initializer || dotDotDotToken) { @@ -2812,6 +2827,11 @@ namespace ts { transformFlags |= TransformFlags.AssertES2017; } + // function declarations with object rest destructuring are ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + // If a FunctionDeclaration's subtree has marked the container as needing to capture the // lexical this, or the function contains parameters with initializers, then this node is // ES6 syntax. @@ -2849,6 +2869,12 @@ namespace ts { transformFlags |= TransformFlags.AssertES2017; } + // function expressions with object rest destructuring are ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + + // If a FunctionExpression's subtree has marked the container as needing to capture the // lexical this, or the function contains parameters with initializers, then this node is // ES6 syntax. @@ -2886,6 +2912,11 @@ namespace ts { transformFlags |= TransformFlags.AssertES2017; } + // arrow functions with object rest destructuring are ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + // If an ArrowFunction contains a lexical this, its container must capture the lexical this. if (subtreeFlags & TransformFlags.ContainsLexicalThis) { transformFlags |= TransformFlags.ContainsCapturedLexicalThis; @@ -2914,8 +2945,13 @@ namespace ts { let transformFlags = subtreeFlags; const nameKind = node.name.kind; - // A VariableDeclaration with a binding pattern is ES6 syntax. - if (nameKind === SyntaxKind.ObjectBindingPattern || nameKind === SyntaxKind.ArrayBindingPattern) { + // A VariableDeclaration with an object binding pattern is ES2015 syntax + // and possibly ESNext syntax if it contains an object binding pattern + if (nameKind === SyntaxKind.ObjectBindingPattern) { + transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; + } + // A VariableDeclaration with an object binding pattern is ES2015 syntax. + else if (nameKind === SyntaxKind.ArrayBindingPattern) { transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; } @@ -3056,6 +3092,10 @@ namespace ts { transformFlags |= TransformFlags.AssertJsx; break; + case SyntaxKind.ForOfStatement: + // for-of might be ESNext if it has a rest destructuring + transformFlags |= TransformFlags.AssertESNext; + // FALLTHROUGH case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.TemplateHead: case SyntaxKind.TemplateMiddle: @@ -3063,7 +3103,6 @@ namespace ts { case SyntaxKind.TemplateExpression: case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.ForOfStatement: case SyntaxKind.StaticKeyword: // These nodes are ES6 syntax. transformFlags |= TransformFlags.AssertES2015; @@ -3129,10 +3168,16 @@ namespace ts { case SyntaxKind.SpreadExpression: case SyntaxKind.SpreadElementExpression: - // This node is ES6 or ES future syntax, but is handled by a containing node. + // This node is ES2015 or ES next syntax, but is handled by a containing node. transformFlags |= TransformFlags.ContainsSpreadExpression; break; + case SyntaxKind.BindingElement: + if ((node as BindingElement).dotDotDotToken) { + // this node is ES2015 or ES next syntax, but is handled by a containing node. + transformFlags |= TransformFlags.ContainsSpreadExpression; + } + case SyntaxKind.SuperKeyword: // This node is ES6 syntax. transformFlags |= TransformFlags.AssertES2015; @@ -3145,8 +3190,13 @@ namespace ts { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: - // These nodes are ES6 syntax. - transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; + // These nodes are ES2015 or ES Next syntax. + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsBindingPattern; + } + else { + transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern; + } break; case SyntaxKind.Decorator: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5447e652f08fe..1c4a135088326 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2245,7 +2245,7 @@ namespace ts { writeUnionOrIntersectionType(type, nextFlags); } else if (type.flags & TypeFlags.Spread) { - writeSpreadType(type); + writeSpreadType(type as SpreadType); } else if (getObjectFlags(type) & ObjectFlags.Anonymous) { writeAnonymousType(type, nextFlags); @@ -3028,26 +3028,31 @@ namespace ts { return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false); } - function getTextOfPropertyName(name: PropertyName): string { - switch (name.kind) { - case SyntaxKind.Identifier: - return (name).text; - case SyntaxKind.StringLiteral: - case SyntaxKind.NumericLiteral: - return (name).text; - case SyntaxKind.ComputedPropertyName: - if (isStringOrNumericLiteral((name).expression.kind)) { - return ((name).expression).text; - } - } - - return undefined; - } - function isComputedNonLiteralName(name: PropertyName): boolean { return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((name).expression.kind); } + function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { + Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now."); + const members = createMap(); + const names = createMap(); + for (const name of properties) { + names[getTextOfPropertyName(name)] = true; + } + for (const prop of getPropertiesOfType(source)) { + const inNamesToRemove = prop.name in names; + const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected); + const isMethod = prop.flags & SymbolFlags.Method; + const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + if (!inNamesToRemove && !isPrivate && !isMethod && !isSetOnlyAccessor) { + members[prop.name] = prop; + } + } + const stringIndexInfo = getIndexInfoOfType(source, IndexKind.String); + const numberIndexInfo = getIndexInfoOfType(source, IndexKind.Number); + return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + } + /** Return the inferred type for a binding element */ function getTypeForBindingElement(declaration: BindingElement): Type { const pattern = declaration.parent; @@ -3068,26 +3073,41 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { - // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) - const name = declaration.propertyName || declaration.name; - if (isComputedNonLiteralName(name)) { - // computed properties with non-literal names are treated as 'any' - return anyType; - } - if (declaration.initializer) { - getContextualType(declaration.initializer); + if (declaration.dotDotDotToken) { + if (!(parentType.flags & TypeFlags.Object)) { + error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); + return unknownType; + } + const literalMembers: PropertyName[] = []; + for (const element of pattern.elements) { + if (element.kind !== SyntaxKind.OmittedExpression && !(element as BindingElement).dotDotDotToken) { + literalMembers.push(element.propertyName || element.name as Identifier); + } + } + type = getRestType(parentType, literalMembers, declaration.symbol); } + else { + // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) + const name = declaration.propertyName || declaration.name; + if (isComputedNonLiteralName(name)) { + // computed properties with non-literal names are treated as 'any' + return anyType; + } + if (declaration.initializer) { + getContextualType(declaration.initializer); + } - // 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. - const text = getTextOfPropertyName(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. + const text = getTextOfPropertyName(name); - type = getTypeOfPropertyOfType(parentType, text) || - isNumericLiteralName(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; + type = getTypeOfPropertyOfType(parentType, text) || + isNumericLiteralName(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; + } } } else { @@ -3295,8 +3315,8 @@ namespace ts { let hasComputedProperties = false; forEach(pattern.elements, e => { const name = e.propertyName || e.name; - if (isComputedNonLiteralName(name)) { - // do not include computed properties in the implied type + if (isComputedNonLiteralName(name) || e.dotDotDotToken) { + // do not include computed properties or rests in the implied type hasComputedProperties = true; return; } @@ -14097,7 +14117,7 @@ namespace ts { error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name)); } } - else { + else if (property.kind !== SyntaxKind.SpreadElementExpression) { error(property, Diagnostics.Property_assignment_expected); } } @@ -14143,7 +14163,7 @@ namespace ts { } else { if (elementIndex < elements.length - 1) { - error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); + error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); } else { const restExpression = (element).expression; @@ -21058,7 +21078,7 @@ namespace ts { if (node.dotDotDotToken) { const elements = (node.parent).elements; if (node !== lastOrUndefined(elements)) { - return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); + return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); } if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1d45e96cb6f6b..5b6d958061eef 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1455,7 +1455,7 @@ "category": "Error", "code": 2461 }, - "A rest element must be last in an array destructuring pattern": { + "A rest element must be last in a destructuring pattern": { "category": "Error", "code": 2462 }, @@ -1991,6 +1991,10 @@ "category": "Error", "code": 2699 }, + "Rest types may only be created from object types.": { + "category": "Error", + "code": 2700 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac41d78bb1232..43182ca83b667 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1274,8 +1274,10 @@ namespace ts { return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); case ParsingContext.ObjectLiteralMembers: return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); + case ParsingContext.RestProperties: + return isLiteralPropertyName(); case ParsingContext.ObjectBindingElements: - return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); + return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); case ParsingContext.HeritageClauseElement: // If we see { } then only consume it as an expression if it is followed by , or { // That way we won't consume the body of a class in its heritage clause. @@ -1402,6 +1404,7 @@ namespace ts { case ParsingContext.ArrayBindingElements: return token() === SyntaxKind.CloseBracketToken; case ParsingContext.Parameters: + case ParsingContext.RestProperties: // 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*/; case ParsingContext.TypeArguments: @@ -1587,6 +1590,9 @@ namespace ts { case ParsingContext.Parameters: return isReusableParameter(node); + case ParsingContext.RestProperties: + return false; + // Any other lists we do not care about reusing nodes in. But feel free to add if // you can do so safely. Danger areas involve nodes that may involve speculative // parsing. If speculative parsing is involved with the node, then the range the @@ -1784,6 +1790,7 @@ namespace ts { case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected; case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected; case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected; + case ParsingContext.RestProperties: // fallthrough case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected; case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected; case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected; @@ -4890,6 +4897,7 @@ namespace ts { function parseObjectBindingElement(): BindingElement { const node = createNode(SyntaxKind.BindingElement); + node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); const tokenIsIdentifier = isIdentifier(); const propertyName = parsePropertyName(); if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) { @@ -5834,6 +5842,7 @@ namespace ts { JsxChildren, // Things between opening and closing JSX tags ArrayLiteralMembers, // Members in array literal Parameters, // Parameters in parameter list + RestProperties, // Property names in a rest type list TypeParameters, // Type parameters in type parameter list TypeArguments, // Type arguments in type argument list TupleElementTypes, // Element types in tuple element type list diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ba5e6b2db9971..b9d223931fc44 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -422,14 +422,15 @@ namespace ts { HasParamDecorators = 1 << 12, // If the file has parameter decorators (initialized by binding) HasAsyncFunctions = 1 << 13, // If the file has async functions (initialized by binding) HasSpreadAttribute = 1 << 14, // If the file as JSX spread attributes (initialized by binding) - DisallowInContext = 1 << 15, // If node was parsed in a context where 'in-expressions' are not allowed - YieldContext = 1 << 16, // If node was parsed in the 'yield' context created when parsing a generator - DecoratorContext = 1 << 17, // If node was parsed as part of a decorator - AwaitContext = 1 << 18, // If node was parsed in the 'await' context created when parsing an async function - ThisNodeHasError = 1 << 19, // If the parser encountered an error when parsing the code that created this node - JavaScriptFile = 1 << 20, // If node was parsed in a JavaScript - ThisNodeOrAnySubNodesHasError = 1 << 21, // If this node or any of its children had an error - HasAggregatedChildData = 1 << 22, // If we've computed data from children and cached it in this node + HasRestAttribute = 1 << 15, // If the file has object destructure elements + DisallowInContext = 1 << 16, // If node was parsed in a context where 'in-expressions' are not allowed + YieldContext = 1 << 17, // If node was parsed in the 'yield' context created when parsing a generator + DecoratorContext = 1 << 18, // If node was parsed as part of a decorator + AwaitContext = 1 << 19, // If node was parsed in the 'await' context created when parsing an async function + ThisNodeHasError = 1 << 20, // If the parser encountered an error when parsing the code that created this node + JavaScriptFile = 1 << 21, // If node was parsed in a JavaScript + ThisNodeOrAnySubNodesHasError = 1 << 22, // If this node or any of its children had an error + HasAggregatedChildData = 1 << 23, // If we've computed data from children and cached it in this node BlockScoped = Let | Const, @@ -651,7 +652,7 @@ namespace ts { export interface BindingElement extends Declaration { kind: SyntaxKind.BindingElement; propertyName?: PropertyName; // Binding property name (in object binding pattern) - dotDotDotToken?: DotDotDotToken; // Present on rest binding element + dotDotDotToken?: DotDotDotToken; // Present on rest element (in object binding pattern) name: BindingName; // Declared binding element name initializer?: Expression; // Optional initializer } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cd3e6ab9575b5..67742347568f4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -485,6 +485,22 @@ namespace ts { return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name); } + export function getTextOfPropertyName(name: PropertyName): string { + switch (name.kind) { + case SyntaxKind.Identifier: + return (name).text; + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + return (name).text; + case SyntaxKind.ComputedPropertyName: + if (isStringOrNumericLiteral((name).expression.kind)) { + return ((name).expression).text; + } + } + + return undefined; + } + export function entityNameToString(name: EntityNameOrEntityNameExpression): string { switch (name.kind) { case SyntaxKind.Identifier: From e3a08ed663446753b1d52a8c1f036560072a4e29 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 14:56:01 -0700 Subject: [PATCH 58/85] Downlevel emit of rest elements --- src/compiler/emitter.ts | 15 + src/compiler/transformers/destructuring.ts | 193 ++++++++-- src/compiler/transformers/esnext.ts | 428 +++++++++++++++++++++ 3 files changed, 596 insertions(+), 40 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0ee598c507aed..c89fa1f155043 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -42,6 +42,15 @@ var __assign = (this && this.__assign) || Object.assign || function(t) { return t; };`; + const restHelper = ` +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) + t[p] = s[p]; + return t; +};`; + // emit output for the __decorate helper function const decorateHelper = ` var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { @@ -226,6 +235,7 @@ const _super = (function (geti, seti) { let currentFileIdentifiers: Map; let extendsEmitted: boolean; let assignEmitted: boolean; + let restEmitted: boolean; let decorateEmitted: boolean; let paramEmitted: boolean; let awaiterEmitted: boolean; @@ -2210,6 +2220,11 @@ const _super = (function (geti, seti) { assignEmitted = true; } + if (!restEmitted && node.flags & NodeFlags.HasRestAttribute) { + writeLines(restHelper); + restEmitted = true; + } + if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) { writeLines(decorateHelper); if (compilerOptions.emitDecoratorMetadata) { diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 89beade577d80..bac8e99420115 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -17,7 +17,8 @@ namespace ts { node: BinaryExpression, needsValue: boolean, recordTempVariable: (node: Identifier) => void, - visitor?: (node: Node) => VisitResult): Expression { + visitor?: (node: Node) => VisitResult, + transformRest?: boolean): Expression { if (isEmptyObjectLiteralOrArrayLiteral(node.left)) { const right = node.right; @@ -51,7 +52,7 @@ namespace ts { location = value; } - flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, visitor); + flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, emitRestAssignment, transformRest, visitor); if (needsValue) { expressions.push(value); @@ -61,7 +62,7 @@ namespace ts { aggregateTransformFlags(expression); return expression; - function emitAssignment(name: Identifier, value: Expression, location: TextRange) { + function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange) { const expression = createAssignment(name, value, location); // NOTE: this completely disables source maps, but aligns with the behavior of @@ -77,6 +78,10 @@ namespace ts { emitAssignment(name, value, location); return name; } + + function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange) { + emitAssignment(createObjectLiteral(elements), value, location); + } } /** @@ -89,14 +94,15 @@ namespace ts { export function flattenParameterDestructuring( node: ParameterDeclaration, value: Expression, - visitor?: (node: Node) => VisitResult) { + visitor?: (node: Node) => VisitResult, + transformRest?: boolean) { const declarations: VariableDeclaration[] = []; - flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor); + flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, emitRestAssignment, transformRest, visitor); return declarations; - function emitAssignment(name: Identifier, value: Expression, location: TextRange) { + function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange) { const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location); // NOTE: this completely disables source maps, but aligns with the behavior of @@ -112,6 +118,10 @@ namespace ts { emitAssignment(name, value, location); return name; } + + function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange) { + emitAssignment(createObjectBindingPattern(elements), value, location); + } } /** @@ -125,15 +135,16 @@ namespace ts { node: VariableDeclaration, value?: Expression, visitor?: (node: Node) => VisitResult, - recordTempVariable?: (node: Identifier) => void) { + recordTempVariable?: (node: Identifier) => void, + transformRest?: boolean) { const declarations: VariableDeclaration[] = []; let pendingAssignments: Expression[]; - flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor); + flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, emitRestAssignment, transformRest, visitor); return declarations; - function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { + function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange, original: Node) { if (pendingAssignments) { pendingAssignments.push(value); value = inlineExpressions(pendingAssignments); @@ -167,6 +178,10 @@ namespace ts { } return name; } + + function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange, original: Node) { + emitAssignment(createObjectBindingPattern(elements), value, location, original); + } } /** @@ -186,15 +201,17 @@ namespace ts { const pendingAssignments: Expression[] = []; - flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, visitor); + flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, emitRestAssignment, /*transformRest*/ false, visitor); const expression = inlineExpressions(pendingAssignments); aggregateTransformFlags(expression); return expression; - function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { + function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange, original: Node) { const expression = createAssignmentCallback - ? createAssignmentCallback(name, value, location) + ? createAssignmentCallback(name.kind === SyntaxKind.Identifier ? name : emitTempVariableAssignment(name, location), + value, + location) : createAssignment(name, value, location); emitPendingAssignment(expression, original); @@ -206,6 +223,10 @@ namespace ts { return name; } + function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange, original: Node) { + emitAssignment(createObjectLiteral(elements), value, location, original); + } + function emitPendingAssignment(expression: Expression, original: Node) { expression.original = original; @@ -223,6 +244,8 @@ namespace ts { location: TextRange, emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void, emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier, + emitRestAssignment: (elements: (ObjectLiteralElementLike[] | BindingElement[]), value: Expression, location: TextRange, original: Node) => void, + transformRest: boolean, visitor?: (node: Node) => VisitResult) { if (value && visitor) { value = visitNode(value, visitor, isExpression); @@ -284,14 +307,39 @@ namespace ts { value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); } - for (const p of properties) { + let es2015: ObjectLiteralElementLike[] = []; + for (let i = 0; i < properties.length; i++) { + const p = properties[i]; if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - const propName = (p).name; - const target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? p : (p).initializer || propName; - // Assignment for target = value.propName should highligh whole property, hence use p as source map node - emitDestructuringAssignment(target, createDestructuringPropertyAccess(value, propName), p); + if (!transformRest || p.transformFlags & TransformFlags.ContainsSpreadExpression) { + if (es2015.length) { + emitRestAssignment(es2015, value, location, target); + es2015 = []; + } + const propName = (p).name; + const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? p : (p).initializer || propName; + // Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node + emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p); + } + else { + es2015.push(p); + } + } + else if (i === properties.length - 1 && p.kind === SyntaxKind.SpreadElementExpression) { + Debug.assert((p as SpreadElementExpression).expression.kind === SyntaxKind.Identifier); + if (es2015.length) { + emitRestAssignment(es2015, value, location, target); + es2015 = []; + } + const propName = (p as SpreadElementExpression).expression as Identifier; + const restCall = createRestCall(value, target.properties, p => p.name, target); + emitDestructuringAssignment(propName, restCall, p); } } + if (es2015.length) { + emitRestAssignment(es2015, value, location, target); + es2015 = []; + } } function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { @@ -318,10 +366,31 @@ namespace ts { } } + /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement + * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/ + function createRestCall(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange): Expression { + const propertyNames: LiteralExpression[] = []; + for (let i = 0; i < elements.length - 1; i++) { + if (isOmittedExpression(elements[i])) { + continue; + } + const str = createSynthesizedNode(SyntaxKind.StringLiteral); + str.pos = location.pos; + str.end = location.end; + str.text = getTextOfPropertyName(getPropertyName(elements[i])); + propertyNames.push(str); + } + const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]); + return createCall(createIdentifier("__rest"), undefined, args); + } + function emitBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) { // Any temporary assignments needed to emit target = value should point to target const initializer = visitor ? visitNode(target.initializer, visitor, isExpression) : target.initializer; - if (initializer) { + if (transformRest) { + value = value || initializer; + } + else if (initializer) { // Combine value and initializer value = value ? createDefaultValueCheck(value, initializer, target) : initializer; } @@ -331,9 +400,11 @@ namespace ts { } const name = target.name; - if (isBindingPattern(name)) { - const elements = name.elements; - const numElements = elements.length; + if (!isBindingPattern(name)) { + emitAssignment(name, value, target, target); + } + else { + const numElements = name.elements.length; if (numElements !== 1) { // For anything other than a single-element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. Additionally, if we have zero elements @@ -341,29 +412,71 @@ namespace ts { // so in that case, we'll intentionally create that temporary. value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment); } - for (let i = 0; i < numElements; i++) { - const element = elements[i]; - if (isOmittedExpression(element)) { - continue; - } - else if (name.kind === SyntaxKind.ObjectBindingPattern) { - // Rewrite element to a declaration with an initializer that fetches property - const propName = element.propertyName || element.name; - emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); + if (name.kind === SyntaxKind.ArrayBindingPattern) { + emitArrayBindingElement(name, value); + } + else { + emitObjectBindingElement(target, value); + } + } + } + + function emitArrayBindingElement(name: BindingPattern, value: Expression) { + const elements = name.elements; + const numElements = elements.length; + for (let i = 0; i < numElements; i++) { + const element = elements[i]; + if (isOmittedExpression(element)) { + continue; + } + if (!element.dotDotDotToken) { + // Rewrite element to a declaration that accesses array element at index i + emitBindingElement(element, createElementAccess(value, i)); + } + else if (i === numElements - 1) { + emitBindingElement(element, createArraySlice(value, i)); + } + } + } + + function emitObjectBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) { + const name = target.name as BindingPattern; + const elements = name.elements; + const numElements = elements.length; + let es2015: BindingElement[] = []; + for (let i = 0; i < numElements; i++) { + const element = elements[i]; + if (isOmittedExpression(element)) { + continue; + } + if (i === numElements - 1 && element.dotDotDotToken) { + if (es2015.length) { + emitRestAssignment(es2015, value, target, target); + es2015 = []; } - else { - if (!element.dotDotDotToken) { - // Rewrite element to a declaration that accesses array element at index i - emitBindingElement(element, createElementAccess(value, i)); - } - else if (i === numElements - 1) { - emitBindingElement(element, createArraySlice(value, i)); - } + const restCall = createRestCall(value, + name.elements, + element => (element as BindingElement).propertyName || (element as BindingElement).name, + name); + emitBindingElement(element, restCall); + } + else if (!transformRest || element.transformFlags & TransformFlags.ContainsSpreadExpression) { + if (es2015.length) { + emitRestAssignment(es2015, value, target, target); + es2015 = []; } + // Rewrite element to a declaration with an initializer that fetches property + const propName = element.propertyName || element.name; + emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); + } + else { + // do not emit until we have a complete bundle of ES2015 syntax + es2015.push(element); } } - else { - emitAssignment(name, value, target, target); + if (es2015.length) { + emitRestAssignment(es2015, value, target, target); + es2015 = []; } } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1a8ed7da5eb4a..a85098f03b6d9 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -4,9 +4,16 @@ /*@internal*/ namespace ts { export function transformESNext(context: TransformationContext) { + const { + startLexicalEnvironment, + endLexicalEnvironment, + hoistVariableDeclaration, + } = context; + let currentSourceFile: SourceFile; return transformSourceFile; function transformSourceFile(node: SourceFile) { + currentSourceFile = node; return visitEachChild(node, visitor, context); } @@ -26,6 +33,23 @@ namespace ts { switch (node.kind) { case SyntaxKind.ObjectLiteralExpression: return visitObjectLiteralExpression(node as ObjectLiteralExpression); + case SyntaxKind.BinaryExpression: + return visitBinaryExpression(node as BinaryExpression); + case SyntaxKind.VariableDeclaration: + return visitVariableDeclaration(node as VariableDeclaration); + case SyntaxKind.ForOfStatement: + return visitForOfStatement(node as ForOfStatement); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return node; + case SyntaxKind.FunctionDeclaration: + return visitFunctionDeclaration(node as FunctionDeclaration); + case SyntaxKind.FunctionExpression: + return visitFunctionExpression(node as FunctionExpression); + case SyntaxKind.ArrowFunction: + return visitArrowFunction(node as ArrowFunction); + case SyntaxKind.Parameter: + return visitParameter(node as ParameterDeclaration); default: Debug.failBadSyntaxKind(node); return visitEachChild(node, visitor, context); @@ -76,5 +100,409 @@ namespace ts { } return createCall(createIdentifier("__assign"), undefined, objects); } + + /** + * Visits a BinaryExpression that contains a destructuring assignment. + * + * @param node A BinaryExpression node. + */ + function visitBinaryExpression(node: BinaryExpression): Expression { + if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.AssertESNext) { + return flattenDestructuringAssignment(context, node, /*needsDestructuringValue*/ true, hoistVariableDeclaration, visitor, /*transformRest*/ true); + } + + return visitEachChild(node, visitor, context); + } + + /** + * Visits a VariableDeclaration node with a binding pattern. + * + * @param node A VariableDeclaration node. + */ + function visitVariableDeclaration(node: VariableDeclaration): VisitResult { + // If we are here it is because the name contains a binding pattern with a rest somewhere in it. + if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.AssertESNext) { + const result = flattenVariableDestructuring(node, /*value*/ undefined, visitor, /*recordTempVariable*/ undefined, /*transformRest*/ true); + return result; + } + + return visitEachChild(node, visitor, context); + } + + /** + * Visits a ForOfStatement and converts it into a ES2015-compatible ForOfStatement. + * + * @param node A ForOfStatement. + */ + function visitForOfStatement(node: ForOfStatement): VisitResult { + // The following ESNext code: + // + // for (let { x, y, ...rest } of expr) { } + // + // should be emitted as + // + // for (var _a of expr) { + // let { x, y } = _a, rest = __rest(_a, ["x", "y"]); + // } + // + // where _a is a temp emitted to capture the RHS. + // When the left hand side is an expression instead of a let declaration, + // the `let` before the `{ x, y }` is not emitted. + // When the left hand side is a let/const, the v is renamed if there is + // another v in scope. + // Note that all assignments to the LHS are emitted in the body, including + // all destructuring. + // Note also that because an extra statement is needed to assign to the LHS, + // for-of bodies are always emitted as blocks. + + // for ( of ) + // where is [let] variabledeclarationlist | expression + const initializer = node.initializer; + if (!isRestBindingPattern(initializer) && !isRestAssignment(initializer)) { + return visitEachChild(node, visitor, context); + } + + const expression = visitNode(node.expression, visitor, isExpression); + const statements: Statement[] = []; + const rhsReference = createTempVariable(/*recordTempVariable*/ undefined); + + // var { x, y } = _a, rest = __rest(_a, ["x", "y"]); + if (isVariableDeclarationList(initializer)) { + // This works whether the declaration is a var, let, or const. + // It will use rhsReference _a as the initializer. + const declarations = flattenVariableDestructuring( + initializer.declarations[0], + rhsReference, + visitor, + /*recordTempVariable*/ undefined, + /*transformRest*/ true, + ); + + const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); + setOriginalNode(declarationList, initializer); + + // Adjust the source map range for the first declaration to align with the old + // emitter. + const firstDeclaration = declarations[0]; + const lastDeclaration = lastOrUndefined(declarations); + setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end)); + + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + declarationList + ) + ); + } + else { + // Initializer is an object literal destructuring assignment. + // Emit the flattened assignments from the object literal expression in the body + const assignment = createAssignment(initializer, rhsReference); + statements.push( + createStatement( + flattenDestructuringAssignment( + context, + assignment, + /*needsValue*/ false, + hoistVariableDeclaration, + visitor, + /*transformRest*/ true + ) + ) + ); + } + + let bodyLocation: TextRange; + let statementsLocation: TextRange; + const statement = visitNode(node.statement, visitor, isStatement); + if (isBlock(statement)) { + addRange(statements, statement.statements); + bodyLocation = statement; + statementsLocation = statement.statements; + } + else { + statements.push(statement); + } + + // The old emitter does not emit source maps for the expression + setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); + + // The old emitter does not emit source maps for the block. + // We add the location to preserve comments. + const body = createBlock( + createNodeArray(statements, /*location*/ statementsLocation), + /*location*/ bodyLocation + ); + + setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); + + const forStatement = createForOf( + createVariableDeclarationList([ + createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression) + ], /*location*/ node.expression), + node.expression, + body, + /*location*/ node + ); + + // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. + setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); + return forStatement; + } + + function isRestBindingPattern(initializer: ForInitializer) { + if (isVariableDeclarationList(initializer)) { + const declaration = firstOrUndefined(initializer.declarations); + return declaration && declaration.name && + declaration.name.kind === SyntaxKind.ObjectBindingPattern && + !!(declaration.name.transformFlags & TransformFlags.ContainsSpreadExpression); + } + return false; + } + + function isRestAssignment(initializer: ForInitializer) { + return initializer.kind === SyntaxKind.ObjectLiteralExpression && + initializer.transformFlags & TransformFlags.ContainsSpreadExpression; + } + + function visitParameter(node: ParameterDeclaration): ParameterDeclaration { + if (isObjectRestParameter(node)) { + // Binding patterns are converted into a generated name and are + // evaluated inside the function body. + return setOriginalNode( + createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + getGeneratedNameForNode(node), + /*questionToken*/ undefined, + /*type*/ undefined, + node.initializer, + /*location*/ node + ), + /*original*/ node + ); + } + else { + return node; + } + } + + function isObjectRestParameter(node: ParameterDeclaration) { + return node.name && + node.name.kind === SyntaxKind.ObjectBindingPattern && + !!(node.name.transformFlags & TransformFlags.ContainsSpreadExpression); + } + + function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { + return setOriginalNode( + createFunctionDeclaration( + /*decorators*/ undefined, + node.modifiers, + node.asteriskToken, + node.name, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBody(node) as Block, + /*location*/ node + ), + /*original*/ node); + } + + function visitArrowFunction(node: ArrowFunction) { + const func = setOriginalNode( + createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + node.equalsGreaterThanToken, + transformFunctionBody(node), + /*location*/ node + ), + /*original*/ node + ); + setEmitFlags(func, EmitFlags.CapturesThis); + return func; + } + + function visitFunctionExpression(node: FunctionExpression): Expression { + return setOriginalNode( + createFunctionExpression( + /*modifiers*/ undefined, + node.asteriskToken, + name, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBody(node) as Block, + /*location*/ node + ), + /*original*/ node + ); + } + + /** + * Transforms the body of a function-like node. + * + * @param node A function-like node. + */ + function transformFunctionBody(node: FunctionLikeDeclaration): Block | Expression { + const hasRest = forEach(node.parameters, isObjectRestParameter); + if (!hasRest) { + return visitEachChild(node.body, visitor, context); + } + + let multiLine = false; // indicates whether the block *must* be emitted as multiple lines + let singleLine = false; // indicates whether the block *may* be emitted as a single line + let statementsLocation: TextRange; + let closeBraceLocation: TextRange; + + const statements: Statement[] = []; + const body = node.body; + let statementOffset: number; + + startLexicalEnvironment(); + if (isBlock(body)) { + // ensureUseStrict is false because no new prologue-directive should be added. + // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array + statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + } + + addDefaultValueAssignmentsIfNeeded(statements, node); + + // If we added any generated statements, this must be a multi-line block. + if (!multiLine && statements.length > 0) { + multiLine = true; + } + + if (isBlock(body)) { + statementsLocation = body.statements; + addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); + + // If the original body was a multi-line block, this must be a multi-line block. + if (!multiLine && body.multiLine) { + multiLine = true; + } + } + else { + Debug.assert(node.kind === SyntaxKind.ArrowFunction); + + // To align with the old emitter, we use a synthetic end position on the location + // for the statement list we synthesize when we down-level an arrow function with + // an expression function body. This prevents both comments and source maps from + // being emitted for the end position only. + statementsLocation = moveRangeEnd(body, -1); + + const equalsGreaterThanToken = (node).equalsGreaterThanToken; + if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) { + if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) { + singleLine = true; + } + else { + multiLine = true; + } + } + + const expression = visitNode(body, visitor, isExpression); + const returnStatement = createReturn(expression, /*location*/ body); + setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); + statements.push(returnStatement); + + // To align with the source map emit for the old emitter, we set a custom + // source map location for the close brace. + closeBraceLocation = body; + } + + const lexicalEnvironment = endLexicalEnvironment(); + addRange(statements, lexicalEnvironment); + + // If we added any final generated statements, this must be a multi-line block + if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { + multiLine = true; + } + + const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); + if (!multiLine && singleLine) { + setEmitFlags(block, EmitFlags.SingleLine); + } + + if (closeBraceLocation) { + setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation); + } + + setOriginalNode(block, node.body); + return block; + } + + function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { + return !!(node.transformFlags & TransformFlags.ContainsDefaultValueAssignments); + } + + /** + * Adds statements to the body of a function-like node if it contains parameters with + * binding patterns or initializers. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + */ + function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void { + if (!shouldAddDefaultValueAssignments(node)) { + return; + } + + for (const parameter of node.parameters) { + // A rest parameter cannot have a binding pattern or an initializer, + // so let's just ignore it. + if (parameter.dotDotDotToken) { + continue; + } + + if (isBindingPattern(parameter.name)) { + addDefaultValueAssignmentForBindingPattern(statements, parameter); + } + } + } + + /** + * Adds statements to the body of a function-like node for parameters with binding patterns + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + */ + function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration): void { + const temp = getGeneratedNameForNode(parameter); + + // In cases where a binding pattern is simply '[]' or '{}', + // we usually don't want to emit a var declaration; however, in the presence + // of an initializer, we must emit that expression to preserve side effects. + if ((parameter.name as BindingPattern).elements.length > 0) { + statements.push( + setEmitFlags( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + flattenParameterDestructuring(parameter, temp, visitor, /*transformRest*/ true) + ) + ), + EmitFlags.CustomPrologue + ) + ); + } + else if (parameter.initializer) { + statements.push( + setEmitFlags( + createStatement( + createAssignment( + temp, + visitNode(parameter.initializer, visitor, isExpression) + ) + ), + EmitFlags.CustomPrologue + ) + ); + } + } } } From ac20b46f4fbd7a526bef4cf3fa20f36b079aee28 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 14:56:58 -0700 Subject: [PATCH 59/85] Add rest tests --- .../conformance/types/rest/objectRest.ts | 33 +++++++++++++++++++ .../types/rest/objectRestAssignment.ts | 7 ++++ .../conformance/types/rest/objectRestForOf.ts | 14 ++++++++ .../types/rest/objectRestNegative.ts | 8 +++++ .../types/rest/objectRestParameter.ts | 8 +++++ .../rest}/restElementMustBeLast.ts | 0 .../cases/fourslash/completionListForRest.ts | 13 ++++++++ tests/cases/fourslash/findAllRefsForRest.ts | 12 +++++++ tests/cases/fourslash/goToDefinitionRest.ts | 12 +++++++ tests/cases/fourslash/renameRest.ts | 15 +++++++++ 10 files changed, 122 insertions(+) create mode 100644 tests/cases/conformance/types/rest/objectRest.ts create mode 100644 tests/cases/conformance/types/rest/objectRestAssignment.ts create mode 100644 tests/cases/conformance/types/rest/objectRestForOf.ts create mode 100644 tests/cases/conformance/types/rest/objectRestNegative.ts create mode 100644 tests/cases/conformance/types/rest/objectRestParameter.ts rename tests/cases/conformance/{es6/destructuring => types/rest}/restElementMustBeLast.ts (100%) create mode 100644 tests/cases/fourslash/completionListForRest.ts create mode 100644 tests/cases/fourslash/findAllRefsForRest.ts create mode 100644 tests/cases/fourslash/goToDefinitionRest.ts create mode 100644 tests/cases/fourslash/renameRest.ts diff --git a/tests/cases/conformance/types/rest/objectRest.ts b/tests/cases/conformance/types/rest/objectRest.ts new file mode 100644 index 0000000000000..f1a77b1c1299d --- /dev/null +++ b/tests/cases/conformance/types/rest/objectRest.ts @@ -0,0 +1,33 @@ +// @target: es2015 +let o = { a: 1, b: 'no' } +var { ...clone } = o; +var { a, ...justB } = o; +var { a, b: renamed, ...empty } = o; +var { ['b']: renamed, ...justA } = o; +var { 'b': renamed, ...justA } = o; +var { b: { '0': n, '1': oooo }, ...justA } = o; + +let o2 = { c: 'terrible idea?', d: 'yes' }; +var { d: renamed, ...d } = o2; + +let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number }; +var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest; + +let complex: { x: { ka, ki }, y: number }; +var { x: { ka, ...nested }, y: other, ...rest } = complex; +({x: { ka, ...nested }, y: other, ...rest} = complex); +var { x, ...fresh } = { x: 1, y: 2 }; +({ x, ...fresh } = { x: 1, y: 2 }); + +class Removable { + private x: number; + protected y: number; + set z(value: number) { } + get both(): number { return 12 } + set both(value: number) { } + m() { } + removed: string; + remainder: string; +} +var removable = new Removable(); +var { removed, ...removableRest } = removable; diff --git a/tests/cases/conformance/types/rest/objectRestAssignment.ts b/tests/cases/conformance/types/rest/objectRestAssignment.ts new file mode 100644 index 0000000000000..19be53d29a3b3 --- /dev/null +++ b/tests/cases/conformance/types/rest/objectRestAssignment.ts @@ -0,0 +1,7 @@ +let x; +let ka; +let nested; +let other; +let rest; +let complex: { x: { ka, ki }, y: number }; +({x: { ka, ...nested }, y: other, ...rest} = complex); diff --git a/tests/cases/conformance/types/rest/objectRestForOf.ts b/tests/cases/conformance/types/rest/objectRestForOf.ts new file mode 100644 index 0000000000000..4f675b1f15b91 --- /dev/null +++ b/tests/cases/conformance/types/rest/objectRestForOf.ts @@ -0,0 +1,14 @@ +// @target: es2015 +let array: { x: number, y: string }[]; +for (let { x, ...restOf } of array) { + [x, restOf]; +} +let xx: number; +let rrestOff: { y: string }; +for ({ x: xx, ...rrestOff } of array ) { + [xx, rrestOff]; +} +for (const norest of array.map(a => ({ ...a, x: 'a string' }))) { + [norest.x, norest.y]; + // x is now a string. who knows why. +} diff --git a/tests/cases/conformance/types/rest/objectRestNegative.ts b/tests/cases/conformance/types/rest/objectRestNegative.ts new file mode 100644 index 0000000000000..7296f2d274e23 --- /dev/null +++ b/tests/cases/conformance/types/rest/objectRestNegative.ts @@ -0,0 +1,8 @@ +let o = { a: 1, b: 'no' }; +var { ...mustBeLast, a } = o; +function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void { +} +function generic(t: T) { + let { x, ...rest } = t; + return rest; +} diff --git a/tests/cases/conformance/types/rest/objectRestParameter.ts b/tests/cases/conformance/types/rest/objectRestParameter.ts new file mode 100644 index 0000000000000..5b47442f047ab --- /dev/null +++ b/tests/cases/conformance/types/rest/objectRestParameter.ts @@ -0,0 +1,8 @@ +// @target: es2015 +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +suddenly(({ x: a, ...rest }) => rest.y); +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); + diff --git a/tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts b/tests/cases/conformance/types/rest/restElementMustBeLast.ts similarity index 100% rename from tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts rename to tests/cases/conformance/types/rest/restElementMustBeLast.ts diff --git a/tests/cases/fourslash/completionListForRest.ts b/tests/cases/fourslash/completionListForRest.ts new file mode 100644 index 0000000000000..b880a90b3dff1 --- /dev/null +++ b/tests/cases/fourslash/completionListForRest.ts @@ -0,0 +1,13 @@ +/// +////interface Gen { +//// x: number; +//// parent: Gen; +//// millenial: string; +////} +////let t: Gen; +////var { x, ...rest } = t; +////rest./*1*/x; +goTo.marker('1'); +verify.memberListContains('parent', '(property) Gen.parent: Gen'); +verify.memberListContains('millenial', '(property) Gen.millenial: string'); +verify.memberListCount(2); diff --git a/tests/cases/fourslash/findAllRefsForRest.ts b/tests/cases/fourslash/findAllRefsForRest.ts new file mode 100644 index 0000000000000..c3a970e9e7359 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForRest.ts @@ -0,0 +1,12 @@ +/// +////interface Gen { +//// x: number +//// [|parent|]: Gen; +//// millenial: string; +////} +////let t: Gen; +////var { x, ...rest } = t; +////rest.[|parent|]; +const ranges = test.ranges(); +verify.referencesOf(ranges[0], ranges); +verify.referencesOf(ranges[1], ranges); diff --git a/tests/cases/fourslash/goToDefinitionRest.ts b/tests/cases/fourslash/goToDefinitionRest.ts new file mode 100644 index 0000000000000..1459b9ffa8845 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionRest.ts @@ -0,0 +1,12 @@ + +/// +////interface Gen { +//// x: number; +//// /*1*/parent: Gen; +//// millenial: string; +////} +////let t: Gen; +////var { x, ...rest } = t; +////rest./*2*/parent; +const ranges = test.ranges(); +verify.goToDefinition('2', [ '1' ]); diff --git a/tests/cases/fourslash/renameRest.ts b/tests/cases/fourslash/renameRest.ts new file mode 100644 index 0000000000000..a5cc2c3868385 --- /dev/null +++ b/tests/cases/fourslash/renameRest.ts @@ -0,0 +1,15 @@ +/// +////interface Gen { +//// x: number; +//// [|parent|]: Gen; +//// millenial: string; +////} +////let t: Gen; +////var { x, ...rest } = t; +////rest.[|parent|]; +const ranges = test.ranges(); +verify.assertHasRanges(ranges); +goTo.position(ranges[0].start); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, ranges); +goTo.position(ranges[1].start); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, ranges); From 9d4ddb68c783de2c67384b408a788d3a2ec59bf8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 14:57:18 -0700 Subject: [PATCH 60/85] Update baselines --- tests/baselines/reference/objectRest.js | 67 + tests/baselines/reference/objectRest.symbols | 146 ++ tests/baselines/reference/objectRest.types | 170 ++ .../reference/objectRestAssignment.js | 25 + .../reference/objectRestAssignment.symbols | 30 + .../reference/objectRestAssignment.types | 36 + tests/baselines/reference/objectRestForOf.js | 45 + .../reference/objectRestForOf.symbols | 50 + .../baselines/reference/objectRestForOf.types | 61 + .../reference/objectRestNegative.errors.txt | 21 + .../baselines/reference/objectRestNegative.js | 27 + .../reference/objectRestParameter.js | 28 + .../reference/objectRestParameter.symbols | 45 + .../reference/objectRestParameter.types | 56 + .../restElementMustBeLast.errors.txt | 10 +- ...ngForObjectBindingPatternDefaultValues2.js | 27 +- ...rObjectBindingPatternDefaultValues2.js.map | 2 +- ...BindingPatternDefaultValues2.sourcemap.txt | 1485 +++++++++-------- 18 files changed, 1582 insertions(+), 749 deletions(-) create mode 100644 tests/baselines/reference/objectRest.js create mode 100644 tests/baselines/reference/objectRest.symbols create mode 100644 tests/baselines/reference/objectRest.types create mode 100644 tests/baselines/reference/objectRestAssignment.js create mode 100644 tests/baselines/reference/objectRestAssignment.symbols create mode 100644 tests/baselines/reference/objectRestAssignment.types create mode 100644 tests/baselines/reference/objectRestForOf.js create mode 100644 tests/baselines/reference/objectRestForOf.symbols create mode 100644 tests/baselines/reference/objectRestForOf.types create mode 100644 tests/baselines/reference/objectRestNegative.errors.txt create mode 100644 tests/baselines/reference/objectRestNegative.js create mode 100644 tests/baselines/reference/objectRestParameter.js create mode 100644 tests/baselines/reference/objectRestParameter.symbols create mode 100644 tests/baselines/reference/objectRestParameter.types diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js new file mode 100644 index 0000000000000..a295ff7b9f1a2 --- /dev/null +++ b/tests/baselines/reference/objectRest.js @@ -0,0 +1,67 @@ +//// [objectRest.ts] +let o = { a: 1, b: 'no' } +var { ...clone } = o; +var { a, ...justB } = o; +var { a, b: renamed, ...empty } = o; +var { ['b']: renamed, ...justA } = o; +var { 'b': renamed, ...justA } = o; +var { b: { '0': n, '1': oooo }, ...justA } = o; + +let o2 = { c: 'terrible idea?', d: 'yes' }; +var { d: renamed, ...d } = o2; + +let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number }; +var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest; + +let complex: { x: { ka, ki }, y: number }; +var { x: { ka, ...nested }, y: other, ...rest } = complex; +({x: { ka, ...nested }, y: other, ...rest} = complex); +var { x, ...fresh } = { x: 1, y: 2 }; +({ x, ...fresh } = { x: 1, y: 2 }); + +class Removable { + private x: number; + protected y: number; + set z(value: number) { } + get both(): number { return 12 } + set both(value: number) { } + m() { } + removed: string; + remainder: string; +} +var removable = new Removable(); +var { removed, ...removableRest } = removable; + + +//// [objectRest.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) + t[p] = s[p]; + return t; +}; +let o = { a: 1, b: 'no' }; +var clone = __rest(o, []); +var { a } = o, justB = __rest(o, ["a"]); +var { a, b: renamed } = o, empty = __rest(o, ["a", "b"]); +var { ['b']: renamed } = o, justA = __rest(o, ["b"]); +var { 'b': renamed } = o, justA = __rest(o, ["b"]); +var { b: { '0': n, '1': oooo } } = o, justA = __rest(o, ["b"]); +let o2 = { c: 'terrible idea?', d: 'yes' }; +var { d: renamed } = o2, d = __rest(o2, ["d"]); +let nestedrest; +var { x } = nestedrest, _a = nestedrest.n1, { y } = _a, _b = _a.n2, { z } = _b, nr = __rest(_b.n3, []), restrest = __rest(nestedrest, ["x", "n1"]); +let complex; +var _c = complex.x, { ka } = _c, nested = __rest(_c, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]); +(_d = complex.x, { ka } = _d, nested = __rest(_d, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]), complex); +var _e = { x: 1, y: 2 }, { x } = _e, fresh = __rest(_e, ["x"]); +(_f = { x: 1, y: 2 }, { x } = _f, fresh = __rest(_f, ["x"]), _f); +class Removable { + set z(value) { } + get both() { return 12; } + set both(value) { } + m() { } +} +var removable = new Removable(); +var { removed } = removable, removableRest = __rest(removable, ["removed"]); +var _d, _f; diff --git a/tests/baselines/reference/objectRest.symbols b/tests/baselines/reference/objectRest.symbols new file mode 100644 index 0000000000000..427656248ee19 --- /dev/null +++ b/tests/baselines/reference/objectRest.symbols @@ -0,0 +1,146 @@ +=== tests/cases/conformance/types/rest/objectRest.ts === +let o = { a: 1, b: 'no' } +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) +>a : Symbol(a, Decl(objectRest.ts, 0, 9)) +>b : Symbol(b, Decl(objectRest.ts, 0, 15)) + +var { ...clone } = o; +>clone : Symbol(clone, Decl(objectRest.ts, 1, 5)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) + +var { a, ...justB } = o; +>a : Symbol(a, Decl(objectRest.ts, 2, 5), Decl(objectRest.ts, 3, 5)) +>justB : Symbol(justB, Decl(objectRest.ts, 2, 8)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) + +var { a, b: renamed, ...empty } = o; +>a : Symbol(a, Decl(objectRest.ts, 2, 5), Decl(objectRest.ts, 3, 5)) +>b : Symbol(b, Decl(objectRest.ts, 0, 15)) +>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) +>empty : Symbol(empty, Decl(objectRest.ts, 3, 20)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) + +var { ['b']: renamed, ...justA } = o; +>'b' : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) +>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) +>justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) + +var { 'b': renamed, ...justA } = o; +>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) +>justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) + +var { b: { '0': n, '1': oooo }, ...justA } = o; +>b : Symbol(b, Decl(objectRest.ts, 0, 15)) +>n : Symbol(n, Decl(objectRest.ts, 6, 10)) +>oooo : Symbol(oooo, Decl(objectRest.ts, 6, 18)) +>justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3)) + +let o2 = { c: 'terrible idea?', d: 'yes' }; +>o2 : Symbol(o2, Decl(objectRest.ts, 8, 3)) +>c : Symbol(c, Decl(objectRest.ts, 8, 10)) +>d : Symbol(d, Decl(objectRest.ts, 8, 31)) + +var { d: renamed, ...d } = o2; +>d : Symbol(d, Decl(objectRest.ts, 8, 31)) +>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) +>d : Symbol(d, Decl(objectRest.ts, 9, 17)) +>o2 : Symbol(o2, Decl(objectRest.ts, 8, 3)) + +let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number }; +>nestedrest : Symbol(nestedrest, Decl(objectRest.ts, 11, 3)) +>x : Symbol(x, Decl(objectRest.ts, 11, 17)) +>n1 : Symbol(n1, Decl(objectRest.ts, 11, 28)) +>y : Symbol(y, Decl(objectRest.ts, 11, 34)) +>n2 : Symbol(n2, Decl(objectRest.ts, 11, 45)) +>z : Symbol(z, Decl(objectRest.ts, 11, 51)) +>n3 : Symbol(n3, Decl(objectRest.ts, 11, 62)) +>n4 : Symbol(n4, Decl(objectRest.ts, 11, 68)) +>rest : Symbol(rest, Decl(objectRest.ts, 11, 86)) +>restrest : Symbol(restrest, Decl(objectRest.ts, 11, 100)) + +var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest; +>x : Symbol(x, Decl(objectRest.ts, 12, 5), Decl(objectRest.ts, 17, 5)) +>n1 : Symbol(n1, Decl(objectRest.ts, 11, 28)) +>y : Symbol(y, Decl(objectRest.ts, 12, 14)) +>n2 : Symbol(n2, Decl(objectRest.ts, 11, 45)) +>z : Symbol(z, Decl(objectRest.ts, 12, 23)) +>n3 : Symbol(n3, Decl(objectRest.ts, 11, 62)) +>nr : Symbol(nr, Decl(objectRest.ts, 12, 32)) +>restrest : Symbol(restrest, Decl(objectRest.ts, 12, 45)) +>nestedrest : Symbol(nestedrest, Decl(objectRest.ts, 11, 3)) + +let complex: { x: { ka, ki }, y: number }; +>complex : Symbol(complex, Decl(objectRest.ts, 14, 3)) +>x : Symbol(x, Decl(objectRest.ts, 14, 14)) +>ka : Symbol(ka, Decl(objectRest.ts, 14, 19)) +>ki : Symbol(ki, Decl(objectRest.ts, 14, 23)) +>y : Symbol(y, Decl(objectRest.ts, 14, 29)) + +var { x: { ka, ...nested }, y: other, ...rest } = complex; +>x : Symbol(x, Decl(objectRest.ts, 14, 14)) +>ka : Symbol(ka, Decl(objectRest.ts, 15, 10)) +>nested : Symbol(nested, Decl(objectRest.ts, 15, 14)) +>y : Symbol(y, Decl(objectRest.ts, 14, 29)) +>other : Symbol(other, Decl(objectRest.ts, 15, 27)) +>rest : Symbol(rest, Decl(objectRest.ts, 15, 37)) +>complex : Symbol(complex, Decl(objectRest.ts, 14, 3)) + +({x: { ka, ...nested }, y: other, ...rest} = complex); +>x : Symbol(x, Decl(objectRest.ts, 16, 2)) +>ka : Symbol(ka, Decl(objectRest.ts, 16, 6)) +>y : Symbol(y, Decl(objectRest.ts, 16, 23)) +>other : Symbol(other, Decl(objectRest.ts, 15, 27)) +>complex : Symbol(complex, Decl(objectRest.ts, 14, 3)) + +var { x, ...fresh } = { x: 1, y: 2 }; +>x : Symbol(x, Decl(objectRest.ts, 12, 5), Decl(objectRest.ts, 17, 5)) +>fresh : Symbol(fresh, Decl(objectRest.ts, 17, 8)) +>x : Symbol(x, Decl(objectRest.ts, 17, 23)) +>y : Symbol(y, Decl(objectRest.ts, 17, 29)) + +({ x, ...fresh } = { x: 1, y: 2 }); +>x : Symbol(x, Decl(objectRest.ts, 18, 2)) +>x : Symbol(x, Decl(objectRest.ts, 18, 20)) +>y : Symbol(y, Decl(objectRest.ts, 18, 26)) + +class Removable { +>Removable : Symbol(Removable, Decl(objectRest.ts, 18, 35)) + + private x: number; +>x : Symbol(Removable.x, Decl(objectRest.ts, 20, 17)) + + protected y: number; +>y : Symbol(Removable.y, Decl(objectRest.ts, 21, 22)) + + set z(value: number) { } +>z : Symbol(Removable.z, Decl(objectRest.ts, 22, 24)) +>value : Symbol(value, Decl(objectRest.ts, 23, 10)) + + get both(): number { return 12 } +>both : Symbol(Removable.both, Decl(objectRest.ts, 23, 28), Decl(objectRest.ts, 24, 36)) + + set both(value: number) { } +>both : Symbol(Removable.both, Decl(objectRest.ts, 23, 28), Decl(objectRest.ts, 24, 36)) +>value : Symbol(value, Decl(objectRest.ts, 25, 13)) + + m() { } +>m : Symbol(Removable.m, Decl(objectRest.ts, 25, 31)) + + removed: string; +>removed : Symbol(Removable.removed, Decl(objectRest.ts, 26, 11)) + + remainder: string; +>remainder : Symbol(Removable.remainder, Decl(objectRest.ts, 27, 20)) +} +var removable = new Removable(); +>removable : Symbol(removable, Decl(objectRest.ts, 30, 3)) +>Removable : Symbol(Removable, Decl(objectRest.ts, 18, 35)) + +var { removed, ...removableRest } = removable; +>removed : Symbol(removed, Decl(objectRest.ts, 31, 5)) +>removableRest : Symbol(removableRest, Decl(objectRest.ts, 31, 14)) +>removable : Symbol(removable, Decl(objectRest.ts, 30, 3)) + diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types new file mode 100644 index 0000000000000..95e378359c8ba --- /dev/null +++ b/tests/baselines/reference/objectRest.types @@ -0,0 +1,170 @@ +=== tests/cases/conformance/types/rest/objectRest.ts === +let o = { a: 1, b: 'no' } +>o : { a: number; b: string; } +>{ a: 1, b: 'no' } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>'no' : "no" + +var { ...clone } = o; +>clone : { a: number; b: string; } +>o : { a: number; b: string; } + +var { a, ...justB } = o; +>a : number +>justB : { b: string; } +>o : { a: number; b: string; } + +var { a, b: renamed, ...empty } = o; +>a : number +>b : any +>renamed : string +>empty : {} +>o : { a: number; b: string; } + +var { ['b']: renamed, ...justA } = o; +>'b' : "b" +>renamed : string +>justA : { a: number; } +>o : { a: number; b: string; } + +var { 'b': renamed, ...justA } = o; +>renamed : string +>justA : { a: number; } +>o : { a: number; b: string; } + +var { b: { '0': n, '1': oooo }, ...justA } = o; +>b : any +>n : string +>oooo : string +>justA : { a: number; } +>o : { a: number; b: string; } + +let o2 = { c: 'terrible idea?', d: 'yes' }; +>o2 : { c: string; d: string; } +>{ c: 'terrible idea?', d: 'yes' } : { c: string; d: string; } +>c : string +>'terrible idea?' : "terrible idea?" +>d : string +>'yes' : "yes" + +var { d: renamed, ...d } = o2; +>d : any +>renamed : string +>d : { c: string; } +>o2 : { c: string; d: string; } + +let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number }; +>nestedrest : { x: number; n1: { y: number; n2: { z: number; n3: { n4: number; }; }; }; rest: number; restrest: number; } +>x : number +>n1 : { y: number; n2: { z: number; n3: { n4: number; }; }; } +>y : number +>n2 : { z: number; n3: { n4: number; }; } +>z : number +>n3 : { n4: number; } +>n4 : number +>rest : number +>restrest : number + +var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest; +>x : number +>n1 : any +>y : number +>n2 : any +>z : number +>n3 : any +>nr : { n4: number; } +>restrest : { rest: number; restrest: number; } +>nestedrest : { x: number; n1: { y: number; n2: { z: number; n3: { n4: number; }; }; }; rest: number; restrest: number; } + +let complex: { x: { ka, ki }, y: number }; +>complex : { x: { ka: any; ki: any; }; y: number; } +>x : { ka: any; ki: any; } +>ka : any +>ki : any +>y : number + +var { x: { ka, ...nested }, y: other, ...rest } = complex; +>x : any +>ka : any +>nested : { ki: any; } +>y : any +>other : number +>rest : {} +>complex : { x: { ka: any; ki: any; }; y: number; } + +({x: { ka, ...nested }, y: other, ...rest} = complex); +>({x: { ka, ...nested }, y: other, ...rest} = complex) : { x: { ka: any; ki: any; }; y: number; } +>{x: { ka, ...nested }, y: other, ...rest} = complex : { x: { ka: any; ki: any; }; y: number; } +>{x: { ka, ...nested }, y: other, ...rest} : { x: { ki: any; ka: any; }; y: number; } +>x : { ki: any; ka: any; } +>{ ka, ...nested } : { ki: any; ka: any; } +>ka : any +>nested : any +>y : number +>other : number +>rest : any +>complex : { x: { ka: any; ki: any; }; y: number; } + +var { x, ...fresh } = { x: 1, y: 2 }; +>x : number +>fresh : { y: number; } +>{ x: 1, y: 2 } : { x: number; y: number; } +>x : number +>1 : 1 +>y : number +>2 : 2 + +({ x, ...fresh } = { x: 1, y: 2 }); +>({ x, ...fresh } = { x: 1, y: 2 }) : { x: number; y: number; } +>{ x, ...fresh } = { x: 1, y: 2 } : { x: number; y: number; } +>{ x, ...fresh } : { y: number; x: number; } +>x : number +>fresh : any +>{ x: 1, y: 2 } : { x: number; y: number; } +>x : number +>1 : 1 +>y : number +>2 : 2 + +class Removable { +>Removable : Removable + + private x: number; +>x : number + + protected y: number; +>y : number + + set z(value: number) { } +>z : number +>value : number + + get both(): number { return 12 } +>both : number +>12 : 12 + + set both(value: number) { } +>both : number +>value : number + + m() { } +>m : () => void + + removed: string; +>removed : string + + remainder: string; +>remainder : string +} +var removable = new Removable(); +>removable : Removable +>new Removable() : Removable +>Removable : typeof Removable + +var { removed, ...removableRest } = removable; +>removed : string +>removableRest : { both: number; remainder: string; } +>removable : Removable + diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js new file mode 100644 index 0000000000000..7ecd54c51527a --- /dev/null +++ b/tests/baselines/reference/objectRestAssignment.js @@ -0,0 +1,25 @@ +//// [objectRestAssignment.ts] +let x; +let ka; +let nested; +let other; +let rest; +let complex: { x: { ka, ki }, y: number }; +({x: { ka, ...nested }, y: other, ...rest} = complex); + + +//// [objectRestAssignment.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) + t[p] = s[p]; + return t; +}; +var x; +var ka; +var nested; +var other; +var rest; +var complex; +(_a = complex.x, (ka = _a.ka, _a), nested = __rest(_a, ["ka"]), (other = complex.y, complex), rest = __rest(complex, ["x", "y"]), complex); +var _a; diff --git a/tests/baselines/reference/objectRestAssignment.symbols b/tests/baselines/reference/objectRestAssignment.symbols new file mode 100644 index 0000000000000..3c54290b5954b --- /dev/null +++ b/tests/baselines/reference/objectRestAssignment.symbols @@ -0,0 +1,30 @@ +=== tests/cases/conformance/types/rest/objectRestAssignment.ts === +let x; +>x : Symbol(x, Decl(objectRestAssignment.ts, 0, 3)) + +let ka; +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 1, 3)) + +let nested; +>nested : Symbol(nested, Decl(objectRestAssignment.ts, 2, 3)) + +let other; +>other : Symbol(other, Decl(objectRestAssignment.ts, 3, 3)) + +let rest; +>rest : Symbol(rest, Decl(objectRestAssignment.ts, 4, 3)) + +let complex: { x: { ka, ki }, y: number }; +>complex : Symbol(complex, Decl(objectRestAssignment.ts, 5, 3)) +>x : Symbol(x, Decl(objectRestAssignment.ts, 5, 14)) +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 5, 19)) +>ki : Symbol(ki, Decl(objectRestAssignment.ts, 5, 23)) +>y : Symbol(y, Decl(objectRestAssignment.ts, 5, 29)) + +({x: { ka, ...nested }, y: other, ...rest} = complex); +>x : Symbol(x, Decl(objectRestAssignment.ts, 6, 2)) +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 6, 6)) +>y : Symbol(y, Decl(objectRestAssignment.ts, 6, 23)) +>other : Symbol(other, Decl(objectRestAssignment.ts, 3, 3)) +>complex : Symbol(complex, Decl(objectRestAssignment.ts, 5, 3)) + diff --git a/tests/baselines/reference/objectRestAssignment.types b/tests/baselines/reference/objectRestAssignment.types new file mode 100644 index 0000000000000..5af3e5872b95e --- /dev/null +++ b/tests/baselines/reference/objectRestAssignment.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/types/rest/objectRestAssignment.ts === +let x; +>x : any + +let ka; +>ka : any + +let nested; +>nested : any + +let other; +>other : any + +let rest; +>rest : any + +let complex: { x: { ka, ki }, y: number }; +>complex : { x: { ka: any; ki: any; }; y: number; } +>x : { ka: any; ki: any; } +>ka : any +>ki : any +>y : number + +({x: { ka, ...nested }, y: other, ...rest} = complex); +>({x: { ka, ...nested }, y: other, ...rest} = complex) : { x: { ka: any; ki: any; }; y: number; } +>{x: { ka, ...nested }, y: other, ...rest} = complex : { x: { ka: any; ki: any; }; y: number; } +>{x: { ka, ...nested }, y: other, ...rest} : { x: { ka: any; }; y: any; } +>x : { ka: any; } +>{ ka, ...nested } : { ka: any; } +>ka : any +>nested : any +>y : any +>other : any +>rest : any +>complex : { x: { ka: any; ki: any; }; y: number; } + diff --git a/tests/baselines/reference/objectRestForOf.js b/tests/baselines/reference/objectRestForOf.js new file mode 100644 index 0000000000000..0a6e2dc40ed34 --- /dev/null +++ b/tests/baselines/reference/objectRestForOf.js @@ -0,0 +1,45 @@ +//// [objectRestForOf.ts] +let array: { x: number, y: string }[]; +for (let { x, ...restOf } of array) { + [x, restOf]; +} +let xx: number; +let rrestOff: { y: string }; +for ({ x: xx, ...rrestOff } of array ) { + [xx, rrestOff]; +} +for (const norest of array.map(a => ({ ...a, x: 'a string' }))) { + [norest.x, norest.y]; + // x is now a string. who knows why. +} + + +//// [objectRestForOf.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) + t[p] = s[p]; + return t; +}; +let array; +for (var _a of array) { + var { x } = _a, restOf = __rest(_a, ["x"]); + [x, restOf]; +} +let xx; +let rrestOff; +for (var _b of array) { + ({ x: xx } = _b, rrestOff = __rest(_b, ["x"])); + [xx, rrestOff]; +} +for (const norest of array.map(a => (__assign({}, a, { x: 'a string' })))) { + [norest.x, norest.y]; +} diff --git a/tests/baselines/reference/objectRestForOf.symbols b/tests/baselines/reference/objectRestForOf.symbols new file mode 100644 index 0000000000000..ec0ccde740d5b --- /dev/null +++ b/tests/baselines/reference/objectRestForOf.symbols @@ -0,0 +1,50 @@ +=== tests/cases/conformance/types/rest/objectRestForOf.ts === +let array: { x: number, y: string }[]; +>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3)) +>x : Symbol(x, Decl(objectRestForOf.ts, 0, 12)) +>y : Symbol(y, Decl(objectRestForOf.ts, 0, 23)) + +for (let { x, ...restOf } of array) { +>x : Symbol(x, Decl(objectRestForOf.ts, 1, 10)) +>restOf : Symbol(restOf, Decl(objectRestForOf.ts, 1, 13)) +>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3)) + + [x, restOf]; +>x : Symbol(x, Decl(objectRestForOf.ts, 1, 10)) +>restOf : Symbol(restOf, Decl(objectRestForOf.ts, 1, 13)) +} +let xx: number; +>xx : Symbol(xx, Decl(objectRestForOf.ts, 4, 3)) + +let rrestOff: { y: string }; +>rrestOff : Symbol(rrestOff, Decl(objectRestForOf.ts, 5, 3)) +>y : Symbol(y, Decl(objectRestForOf.ts, 5, 15)) + +for ({ x: xx, ...rrestOff } of array ) { +>x : Symbol(x, Decl(objectRestForOf.ts, 6, 6)) +>xx : Symbol(xx, Decl(objectRestForOf.ts, 4, 3)) +>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3)) + + [xx, rrestOff]; +>xx : Symbol(xx, Decl(objectRestForOf.ts, 4, 3)) +>rrestOff : Symbol(rrestOff, Decl(objectRestForOf.ts, 5, 3)) +} +for (const norest of array.map(a => ({ ...a, x: 'a string' }))) { +>norest : Symbol(norest, Decl(objectRestForOf.ts, 9, 10)) +>array.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(objectRestForOf.ts, 9, 31)) +>x : Symbol(x, Decl(objectRestForOf.ts, 9, 44)) + + [norest.x, norest.y]; +>norest.x : Symbol(x, Decl(objectRestForOf.ts, 9, 44)) +>norest : Symbol(norest, Decl(objectRestForOf.ts, 9, 10)) +>x : Symbol(x, Decl(objectRestForOf.ts, 9, 44)) +>norest.y : Symbol(y, Decl(objectRestForOf.ts, 0, 23)) +>norest : Symbol(norest, Decl(objectRestForOf.ts, 9, 10)) +>y : Symbol(y, Decl(objectRestForOf.ts, 0, 23)) + + // x is now a string. who knows why. +} + diff --git a/tests/baselines/reference/objectRestForOf.types b/tests/baselines/reference/objectRestForOf.types new file mode 100644 index 0000000000000..e8c3b4a82abf1 --- /dev/null +++ b/tests/baselines/reference/objectRestForOf.types @@ -0,0 +1,61 @@ +=== tests/cases/conformance/types/rest/objectRestForOf.ts === +let array: { x: number, y: string }[]; +>array : { x: number; y: string; }[] +>x : number +>y : string + +for (let { x, ...restOf } of array) { +>x : number +>restOf : { y: string; } +>array : { x: number; y: string; }[] + + [x, restOf]; +>[x, restOf] : (number | { y: string; })[] +>x : number +>restOf : { y: string; } +} +let xx: number; +>xx : number + +let rrestOff: { y: string }; +>rrestOff : { y: string; } +>y : string + +for ({ x: xx, ...rrestOff } of array ) { +>{ x: xx, ...rrestOff } : { y: string; x: number; } +>x : { x: number; y: string; } +>xx : number +>rrestOff : any +>array : { x: number; y: string; }[] + + [xx, rrestOff]; +>[xx, rrestOff] : (number | { y: string; })[] +>xx : number +>rrestOff : { y: string; } +} +for (const norest of array.map(a => ({ ...a, x: 'a string' }))) { +>norest : { x: string; y: string; } +>array.map(a => ({ ...a, x: 'a string' })) : { x: string; y: string; }[] +>array.map : { (this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U, U]; (this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U]; (this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U]; (this: [{ x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U]; (callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): U[]; } +>array : { x: number; y: string; }[] +>map : { (this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U, U]; (this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U]; (this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U]; (this: [{ x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U]; (callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): U[]; } +>a => ({ ...a, x: 'a string' }) : (a: { x: number; y: string; }) => { x: string; y: string; } +>a : { x: number; y: string; } +>({ ...a, x: 'a string' }) : { x: string; y: string; } +>{ ...a, x: 'a string' } : { x: string; y: string; } +>a : any +>x : string +>'a string' : "a string" + + [norest.x, norest.y]; +>[norest.x, norest.y] : string[] +>norest.x : string +>norest : { x: string; y: string; } +>x : string +>norest.y : string +>norest : { x: string; y: string; } +>y : string + + // x is now a string. who knows why. +} + diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt new file mode 100644 index 0000000000000..1874570da7c9f --- /dev/null +++ b/tests/baselines/reference/objectRestNegative.errors.txt @@ -0,0 +1,21 @@ +tests/cases/conformance/types/rest/objectRestNegative.ts(2,10): error TS2462: A rest element must be last in a destructuring pattern +tests/cases/conformance/types/rest/objectRestNegative.ts(3,31): error TS2462: A rest element must be last in a destructuring pattern +tests/cases/conformance/types/rest/objectRestNegative.ts(6,17): error TS2700: Rest types may only be created from object types. + + +==== tests/cases/conformance/types/rest/objectRestNegative.ts (3 errors) ==== + let o = { a: 1, b: 'no' }; + var { ...mustBeLast, a } = o; + ~~~~~~~~~~ +!!! error TS2462: A rest element must be last in a destructuring pattern + function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void { + ~~~~~~~~~~ +!!! error TS2462: A rest element must be last in a destructuring pattern + } + function generic(t: T) { + let { x, ...rest } = t; + ~~~~ +!!! error TS2700: Rest types may only be created from object types. + return rest; + } + \ No newline at end of file diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js new file mode 100644 index 0000000000000..b3b49740762aa --- /dev/null +++ b/tests/baselines/reference/objectRestNegative.js @@ -0,0 +1,27 @@ +//// [objectRestNegative.ts] +let o = { a: 1, b: 'no' }; +var { ...mustBeLast, a } = o; +function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void { +} +function generic(t: T) { + let { x, ...rest } = t; + return rest; +} + + +//// [objectRestNegative.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) + t[p] = s[p]; + return t; +}; +var o = { a: 1, b: 'no' }; +var mustBeLast = o.mustBeLast, a = o.a; +function stillMustBeLast(_a) { + var mustBeLast = _a.mustBeLast, a = _a.a; +} +function generic(t) { + var x = t.x, rest = __rest(t, ["x"]); + return rest; +} diff --git a/tests/baselines/reference/objectRestParameter.js b/tests/baselines/reference/objectRestParameter.js new file mode 100644 index 0000000000000..49434f24eece7 --- /dev/null +++ b/tests/baselines/reference/objectRestParameter.js @@ -0,0 +1,28 @@ +//// [objectRestParameter.ts] +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +suddenly(({ x: a, ...rest }) => rest.y); +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); + + + +//// [objectRestParameter.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) + t[p] = s[p]; + return t; +}; +function cloneAgain(_a) { + var { a } = _a, clone = __rest(_a, ["a"]); +} +suddenly((_a) => { + var { x: a } = _a, rest = __rest(_a, ["x"]); + return rest.y; +}); +suddenly((_a = { x: { z: 1, ka: 1 }, y: 'noo' }) => { + var _b = _a.x, { z = 12 } = _b, nested = __rest(_b, ["z"]), rest = __rest(_a, ["x"]); + return rest.y + nested.ka; +}); diff --git a/tests/baselines/reference/objectRestParameter.symbols b/tests/baselines/reference/objectRestParameter.symbols new file mode 100644 index 0000000000000..9569dc53d3a86 --- /dev/null +++ b/tests/baselines/reference/objectRestParameter.symbols @@ -0,0 +1,45 @@ +=== tests/cases/conformance/types/rest/objectRestParameter.ts === +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +>cloneAgain : Symbol(cloneAgain, Decl(objectRestParameter.ts, 0, 0)) +>a : Symbol(a, Decl(objectRestParameter.ts, 0, 21)) +>clone : Symbol(clone, Decl(objectRestParameter.ts, 0, 24)) +>a : Symbol(a, Decl(objectRestParameter.ts, 0, 38)) +>b : Symbol(b, Decl(objectRestParameter.ts, 0, 49)) +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +>suddenly : Symbol(suddenly, Decl(objectRestParameter.ts, 1, 1)) +>f : Symbol(f, Decl(objectRestParameter.ts, 3, 26)) +>a : Symbol(a, Decl(objectRestParameter.ts, 3, 30)) +>x : Symbol(x, Decl(objectRestParameter.ts, 3, 34)) +>z : Symbol(z, Decl(objectRestParameter.ts, 3, 39)) +>ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42)) +>y : Symbol(y, Decl(objectRestParameter.ts, 3, 48)) + +suddenly(({ x: a, ...rest }) => rest.y); +>suddenly : Symbol(suddenly, Decl(objectRestParameter.ts, 1, 1)) +>x : Symbol(x, Decl(objectRestParameter.ts, 3, 34)) +>a : Symbol(a, Decl(objectRestParameter.ts, 4, 11)) +>rest : Symbol(rest, Decl(objectRestParameter.ts, 4, 17)) +>rest.y : Symbol(y, Decl(objectRestParameter.ts, 3, 48)) +>rest : Symbol(rest, Decl(objectRestParameter.ts, 4, 17)) +>y : Symbol(y, Decl(objectRestParameter.ts, 3, 48)) + +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); +>suddenly : Symbol(suddenly, Decl(objectRestParameter.ts, 1, 1)) +>x : Symbol(x, Decl(objectRestParameter.ts, 3, 34)) +>z : Symbol(z, Decl(objectRestParameter.ts, 5, 16)) +>nested : Symbol(nested, Decl(objectRestParameter.ts, 5, 24)) +>rest : Symbol(rest, Decl(objectRestParameter.ts, 5, 37)) +>x : Symbol(x, Decl(objectRestParameter.ts, 5, 51)) +>z : Symbol(z, Decl(objectRestParameter.ts, 5, 56)) +>ka : Symbol(ka, Decl(objectRestParameter.ts, 5, 62)) +>y : Symbol(y, Decl(objectRestParameter.ts, 5, 71)) +>rest.y : Symbol(y, Decl(objectRestParameter.ts, 3, 48)) +>rest : Symbol(rest, Decl(objectRestParameter.ts, 5, 37)) +>y : Symbol(y, Decl(objectRestParameter.ts, 3, 48)) +>nested.ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42)) +>nested : Symbol(nested, Decl(objectRestParameter.ts, 5, 24)) +>ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42)) + + diff --git a/tests/baselines/reference/objectRestParameter.types b/tests/baselines/reference/objectRestParameter.types new file mode 100644 index 0000000000000..c634c9c5cd530 --- /dev/null +++ b/tests/baselines/reference/objectRestParameter.types @@ -0,0 +1,56 @@ +=== tests/cases/conformance/types/rest/objectRestParameter.ts === +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +>cloneAgain : ({a, ...clone}: { a: number; b: string; }) => void +>a : number +>clone : { b: string; } +>a : number +>b : string +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any +>f : (a: { x: { z: any; ka: any; }; y: string; }) => void +>a : { x: { z: any; ka: any; }; y: string; } +>x : { z: any; ka: any; } +>z : any +>ka : any +>y : string + +suddenly(({ x: a, ...rest }) => rest.y); +>suddenly(({ x: a, ...rest }) => rest.y) : any +>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any +>({ x: a, ...rest }) => rest.y : ({x: a, ...rest}: { x: { z: any; ka: any; }; y: string; }) => string +>x : any +>a : { z: any; ka: any; } +>rest : { y: string; } +>rest.y : string +>rest : { y: string; } +>y : string + +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); +>suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka) : any +>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any +>({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka : ({x: {z, ...nested}, ...rest}?: { x: { z: any; ka: any; }; y: string; }) => string +>x : any +>z : any +>12 : 12 +>nested : { ka: any; } +>rest : { y: string; } +>{ x: { z: 1, ka: 1 }, y: 'noo' } : { x: { z: number; ka: number; }; y: string; } +>x : { z: number; ka: number; } +>{ z: 1, ka: 1 } : { z: number; ka: number; } +>z : number +>1 : 1 +>ka : number +>1 : 1 +>y : string +>'noo' : "noo" +>rest.y + nested.ka : string +>rest.y : string +>rest : { y: string; } +>y : string +>nested.ka : any +>nested : { ka: any; } +>ka : any + + diff --git a/tests/baselines/reference/restElementMustBeLast.errors.txt b/tests/baselines/reference/restElementMustBeLast.errors.txt index 269d984bc009c..5eb5a4cd2080f 100644 --- a/tests/baselines/reference/restElementMustBeLast.errors.txt +++ b/tests/baselines/reference/restElementMustBeLast.errors.txt @@ -1,12 +1,12 @@ -tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts(1,9): error TS2462: A rest element must be last in an array destructuring pattern -tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts(2,2): error TS2462: A rest element must be last in an array destructuring pattern +tests/cases/conformance/types/rest/restElementMustBeLast.ts(1,9): error TS2462: A rest element must be last in a destructuring pattern +tests/cases/conformance/types/rest/restElementMustBeLast.ts(2,2): error TS2462: A rest element must be last in a destructuring pattern -==== tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts (2 errors) ==== +==== tests/cases/conformance/types/rest/restElementMustBeLast.ts (2 errors) ==== var [...a, x] = [1, 2, 3]; // Error, rest must be last element ~ -!!! error TS2462: A rest element must be last in an array destructuring pattern +!!! error TS2462: A rest element must be last in a destructuring pattern [...a, x] = [1, 2, 3]; // Error, rest must be last element ~~~~ -!!! error TS2462: A rest element must be last in an array destructuring pattern +!!! error TS2462: A rest element must be last in a destructuring pattern \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js index 9f7a70699bd1f..8355d61d9c38a 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js +++ b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js @@ -194,13 +194,13 @@ for (_b = getRobot(), _c = _b.name, nameA = _c === void 0 ? "noName" : _c, _b, i for (_d = { name: "trimmer", skill: "trimming" }, _e = _d.name, nameA = _e === void 0 ? "noName" : _e, _d, i = 0; i < 1; i++) { console.log(nameA); } -for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, i = 0; i < 1; i++) { +for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_k = getMultiRobot(), _l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k, i = 0; i < 1; i++) { +for (_k = getMultiRobot(), (_l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k), _k, i = 0; i < 1; i++) { console.log(primaryA); } -for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q, +for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q), _q, i = 0; i < 1; i++) { console.log(primaryA); } @@ -213,13 +213,13 @@ for (_w = getRobot(), _x = _w.name, name = _x === void 0 ? "noName" : _x, _w, i for (_y = { name: "trimmer", skill: "trimming" }, _z = _y.name, name = _z === void 0 ? "noName" : _z, _y, i = 0; i < 1; i++) { console.log(nameA); } -for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, i = 0; i < 1; i++) { +for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_4 = getMultiRobot(), _5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4, i = 0; i < 1; i++) { +for (_4 = getMultiRobot(), (_5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4), _4, i = 0; i < 1; i++) { console.log(primaryA); } -for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9, +for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9), _9, i = 0; i < 1; i++) { console.log(primaryA); } @@ -232,13 +232,13 @@ for (_16 = getRobot(), _17 = _16.name, nameA = _17 === void 0 ? "noName" : _17, for (_19 = { name: "trimmer", skill: "trimming" }, _20 = _19.name, nameA = _20 === void 0 ? "noName" : _20, _21 = _19.skill, skillA = _21 === void 0 ? "skill" : _21, _19, i = 0; i < 1; i++) { console.log(nameA); } -for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, i = 0; i < 1; i++) { +for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_27 = getMultiRobot(), _28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27, i = 0; i < 1; i++) { +for (_27 = getMultiRobot(), (_28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27), _27, i = 0; i < 1; i++) { console.log(primaryA); } -for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33, +for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33), _33, i = 0; i < 1; i++) { console.log(primaryA); } @@ -251,15 +251,16 @@ for (_41 = getRobot(), _42 = _41.name, name = _42 === void 0 ? "noName" : _42, _ for (_44 = { name: "trimmer", skill: "trimming" }, _45 = _44.name, name = _45 === void 0 ? "noName" : _45, _46 = _44.skill, skill = _46 === void 0 ? "skill" : _46, _44, i = 0; i < 1; i++) { console.log(nameA); } -for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, i = 0; i < 1; i++) { +for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, multiRobot, i = 0; i < 1; i++) { console.log(primaryA); } -for (_52 = getMultiRobot(), _53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52, i = 0; i < 1; i++) { +for (_52 = getMultiRobot(), (_53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52), _52, i = 0; i < 1; i++) { console.log(primaryA); } -for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58, +for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58), _58, i = 0; i < 1; i++) { console.log(primaryA); } -var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63; +var _k, _q, _4, _9, _27, _33, _52, _58; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _l, _m, _o, _p, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _5, _6, _7, _8, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _28, _29, _30, _31, _32, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _53, _54, _55, _56, _57, _59, _60, _61, _62, _63; //# sourceMappingURL=sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map index dd248e8994414..56f8aa0f607ef 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map +++ b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map] -{"version":3,"file":"sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js","sourceRoot":"","sources":["sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.ts"],"names":[],"mappings":"AAgBA,IAAI,KAAK,GAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACtD,IAAI,UAAU,GAAe,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AACjG;IACI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;IACI,MAAM,CAAC,UAAU,CAAC;AACtB,CAAC;AAED,IAAI,KAAa,EAAE,QAAgB,EAAE,UAAkB,EAAE,CAAS,EAAE,MAAc,CAAC;AACnF,IAAI,IAAY,EAAE,OAAe,EAAE,SAAiB,EAAE,KAAa,CAAC;AAEpE,GAAG,CAAC,CAAE,eAAsB,EAAtB,qCAAsB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAsC,EAArC,YAAsB,EAAtB,qCAAsB,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAyE,EAAxE,YAAsB,EAAtB,qCAAsB,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,EAEvC,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,EAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,MAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,EAJrF,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,eAAe,EAAf,oCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAgC,EAA9B,YAAe,EAAf,oCAAe,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAmE,EAAjE,YAAe,EAAf,oCAAe,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,EAE3B,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,EAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,MAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,EAJrF,eAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAGD,GAAG,CAAC,CAAE,gBAAsB,EAAtB,uCAAsB,EAAE,iBAAuB,EAAvB,uCAAuB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAA+D,EAA9D,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAkG,EAAjG,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACzH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAsB,EAAtB,uCAAsB,EACtB,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,EAEvC,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,EALf,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,OAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,EALrF,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,gBAAe,EAAf,sCAAe,EAAE,iBAAe,EAAf,sCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAAiD,EAA/C,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAoF,EAAlF,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC3G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAe,EAAf,sCAAe,EACf,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,EAE3B,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,EALf,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,OAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,EALrF,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js","sourceRoot":"","sources":["sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.ts"],"names":[],"mappings":"AAgBA,IAAI,KAAK,GAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACtD,IAAI,UAAU,GAAe,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;AACjG;IACI,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC;AACD;IACI,MAAM,CAAC,UAAU,CAAC;AACtB,CAAC;AAED,IAAI,KAAa,EAAE,QAAgB,EAAE,UAAkB,EAAE,CAAS,EAAE,MAAc,CAAC;AACnF,IAAI,IAAY,EAAE,OAAe,EAAE,SAAiB,EAAE,KAAa,CAAC;AAEpE,GAAG,CAAC,CAAE,eAAsB,EAAtB,qCAAsB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAsC,EAArC,YAAsB,EAAtB,qCAAsB,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAyE,EAAxE,YAAsB,EAAtB,qCAAsB,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,EAEvC,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,GAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC,WAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,GAJrF,cAG0C,EAH1C,gEAG0C,EAFtC,eAA6B,EAA7B,yCAA6B,EAC7B,iBAAmC,EAAnC,6CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,eAAe,EAAf,oCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,eAAgC,EAA9B,YAAe,EAAf,oCAAe,MAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,2CAAmE,EAAjE,YAAe,EAAf,oCAAe,MAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC1F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,sBAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,EAE3B,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,oBAKc,GAJf,cAG0C,EAH1C,gEAG0C,EAFtC,eAAmB,EAAnB,wCAAmB,EACnB,iBAAuB,EAAvB,4CAAuB,WAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,8EAKoF,GAJrF,eAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAGD,GAAG,CAAC,CAAE,gBAAsB,EAAtB,uCAAsB,EAAE,iBAAuB,EAAvB,uCAAuB,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAA+D,EAA9D,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAkG,EAAjG,cAAsB,EAAtB,uCAAsB,EAAE,eAAuB,EAAvB,uCAAuB,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACzH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAsB,EAAtB,uCAAsB,EACtB,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,EAEvC,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,GALf,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC,aAEtB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,GALrF,cAAsB,EAAtB,uCAAsB,EACtB,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAA6B,EAA7B,2CAA6B,EAC7B,mBAAmC,EAAnC,+CAAmC;IAGvC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,GAAG,CAAC,CAAG,gBAAe,EAAf,sCAAe,EAAE,iBAAe,EAAf,sCAAe,EAAK,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,gBAAiD,EAA/C,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CAAC,4CAAoF,EAAlF,cAAe,EAAf,sCAAe,EAAE,eAAe,EAAf,sCAAe,OAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAC3G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AACD,GAAG,CAAC,CACA,qBAAe,EAAf,sCAAe,EACf,uBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,EAE3B,UAAU,EAAV,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,qBAMc,GALf,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB,aAEV,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AACD,GAAG,CAAC,CAAC,+EAMoF,GALrF,cAAe,EAAf,sCAAe,EACf,gBAG0C,EAH1C,mEAG0C,EAFtC,iBAAmB,EAAnB,0CAAmB,EACnB,mBAAuB,EAAvB,8CAAuB;IAG3B,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt index 97271e8f3d039..9e0e92d4a689e 100644 --- a/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.sourcemap.txt @@ -594,14 +594,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(19, 1) Source(37, 1) + SourceIndex(0) 2 >Emitted(19, 2) Source(37, 2) + SourceIndex(0) --- ->>>for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, i = 0; i < 1; i++) { +>>>for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -620,18 +620,20 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 16> ^^ 17> ^^^^^^^^^^ 18> ^^ -19> ^ -20> ^^^ -21> ^ -22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^ -29> ^^ -30> ^ +19> ^^^^^^^^^^ +20> ^^ +21> ^ +22> ^^^ +23> ^ +24> ^^ +25> ^ +26> ^^^ +27> ^ +28> ^^ +29> ^ +30> ^^ +31> ^^ +32> ^ 1-> > 2 >for @@ -660,19 +662,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 17> multiRobot -18> , -19> i -20> = -21> 0 -22> ; -23> i -24> < -25> 1 -26> ; -27> i -28> ++ -29> ) -30> { +18> +19> multiRobot +20> , +21> i +22> = +23> 0 +24> ; +25> i +26> < +27> 1 +28> ; +29> i +30> ++ +31> ) +32> { 1->Emitted(20, 1) Source(38, 1) + SourceIndex(0) 2 >Emitted(20, 4) Source(38, 4) + SourceIndex(0) 3 >Emitted(20, 5) Source(38, 5) + SourceIndex(0) @@ -690,19 +694,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 15>Emitted(20, 220) Source(41, 44) + SourceIndex(0) 16>Emitted(20, 222) Source(43, 5) + SourceIndex(0) 17>Emitted(20, 232) Source(43, 15) + SourceIndex(0) -18>Emitted(20, 234) Source(43, 17) + SourceIndex(0) -19>Emitted(20, 235) Source(43, 18) + SourceIndex(0) -20>Emitted(20, 238) Source(43, 21) + SourceIndex(0) -21>Emitted(20, 239) Source(43, 22) + SourceIndex(0) -22>Emitted(20, 241) Source(43, 24) + SourceIndex(0) -23>Emitted(20, 242) Source(43, 25) + SourceIndex(0) -24>Emitted(20, 245) Source(43, 28) + SourceIndex(0) -25>Emitted(20, 246) Source(43, 29) + SourceIndex(0) -26>Emitted(20, 248) Source(43, 31) + SourceIndex(0) -27>Emitted(20, 249) Source(43, 32) + SourceIndex(0) -28>Emitted(20, 251) Source(43, 34) + SourceIndex(0) -29>Emitted(20, 253) Source(43, 36) + SourceIndex(0) -30>Emitted(20, 254) Source(43, 37) + SourceIndex(0) +18>Emitted(20, 234) Source(43, 5) + SourceIndex(0) +19>Emitted(20, 244) Source(43, 15) + SourceIndex(0) +20>Emitted(20, 246) Source(43, 17) + SourceIndex(0) +21>Emitted(20, 247) Source(43, 18) + SourceIndex(0) +22>Emitted(20, 250) Source(43, 21) + SourceIndex(0) +23>Emitted(20, 251) Source(43, 22) + SourceIndex(0) +24>Emitted(20, 253) Source(43, 24) + SourceIndex(0) +25>Emitted(20, 254) Source(43, 25) + SourceIndex(0) +26>Emitted(20, 257) Source(43, 28) + SourceIndex(0) +27>Emitted(20, 258) Source(43, 29) + SourceIndex(0) +28>Emitted(20, 260) Source(43, 31) + SourceIndex(0) +29>Emitted(20, 261) Source(43, 32) + SourceIndex(0) +30>Emitted(20, 263) Source(43, 34) + SourceIndex(0) +31>Emitted(20, 265) Source(43, 36) + SourceIndex(0) +32>Emitted(20, 266) Source(43, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -734,44 +740,44 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(22, 1) Source(45, 1) + SourceIndex(0) 2 >Emitted(22, 2) Source(45, 2) + SourceIndex(0) --- ->>>for (_k = getMultiRobot(), _l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k, i = 0; i < 1; i++) { +>>>for (_k = getMultiRobot(), (_l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k), _k, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^^^^^ -19> ^ -20> ^^^ -21> ^ -22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^ -29> ^^ -30> ^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^^^^^^^^^^ +19> ^ +20> ^^^ +21> ^ +22> ^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^ +29> ^^ +30> ^ 1-> > 2 >for @@ -784,69 +790,69 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary: primaryA = "primary" -12> -13> primary: primaryA = "primary" -14> , - > -15> secondary: secondaryA = "secondary" -16> -17> secondary: secondaryA = "secondary" -18> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -19> i -20> = -21> 0 -22> ; -23> i -24> < -25> 1 -26> ; -27> i -28> ++ -29> ) -30> { +7 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary: primaryA = "primary" +12> +13> primary: primaryA = "primary" +14> , + > +15> secondary: secondaryA = "secondary" +16> +17> secondary: secondaryA = "secondary" +18> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +19> i +20> = +21> 0 +22> ; +23> i +24> < +25> 1 +26> ; +27> i +28> ++ +29> ) +30> { 1->Emitted(23, 1) Source(46, 1) + SourceIndex(0) 2 >Emitted(23, 4) Source(46, 4) + SourceIndex(0) 3 >Emitted(23, 5) Source(46, 5) + SourceIndex(0) 4 >Emitted(23, 6) Source(46, 6) + SourceIndex(0) 5 >Emitted(23, 26) Source(51, 20) + SourceIndex(0) -6 >Emitted(23, 28) Source(47, 5) + SourceIndex(0) -7 >Emitted(23, 42) Source(50, 47) + SourceIndex(0) -8 >Emitted(23, 44) Source(47, 5) + SourceIndex(0) -9 >Emitted(23, 108) Source(50, 47) + SourceIndex(0) -10>Emitted(23, 110) Source(48, 9) + SourceIndex(0) -11>Emitted(23, 125) Source(48, 38) + SourceIndex(0) -12>Emitted(23, 127) Source(48, 9) + SourceIndex(0) -13>Emitted(23, 168) Source(48, 38) + SourceIndex(0) -14>Emitted(23, 170) Source(49, 9) + SourceIndex(0) -15>Emitted(23, 187) Source(49, 44) + SourceIndex(0) -16>Emitted(23, 189) Source(49, 9) + SourceIndex(0) -17>Emitted(23, 234) Source(49, 44) + SourceIndex(0) -18>Emitted(23, 240) Source(51, 22) + SourceIndex(0) -19>Emitted(23, 241) Source(51, 23) + SourceIndex(0) -20>Emitted(23, 244) Source(51, 26) + SourceIndex(0) -21>Emitted(23, 245) Source(51, 27) + SourceIndex(0) -22>Emitted(23, 247) Source(51, 29) + SourceIndex(0) -23>Emitted(23, 248) Source(51, 30) + SourceIndex(0) -24>Emitted(23, 251) Source(51, 33) + SourceIndex(0) -25>Emitted(23, 252) Source(51, 34) + SourceIndex(0) -26>Emitted(23, 254) Source(51, 36) + SourceIndex(0) -27>Emitted(23, 255) Source(51, 37) + SourceIndex(0) -28>Emitted(23, 257) Source(51, 39) + SourceIndex(0) -29>Emitted(23, 259) Source(51, 41) + SourceIndex(0) -30>Emitted(23, 260) Source(51, 42) + SourceIndex(0) +6 >Emitted(23, 29) Source(47, 5) + SourceIndex(0) +7 >Emitted(23, 43) Source(50, 47) + SourceIndex(0) +8 >Emitted(23, 45) Source(47, 5) + SourceIndex(0) +9 >Emitted(23, 109) Source(50, 47) + SourceIndex(0) +10>Emitted(23, 111) Source(48, 9) + SourceIndex(0) +11>Emitted(23, 126) Source(48, 38) + SourceIndex(0) +12>Emitted(23, 128) Source(48, 9) + SourceIndex(0) +13>Emitted(23, 169) Source(48, 38) + SourceIndex(0) +14>Emitted(23, 171) Source(49, 9) + SourceIndex(0) +15>Emitted(23, 188) Source(49, 44) + SourceIndex(0) +16>Emitted(23, 190) Source(49, 9) + SourceIndex(0) +17>Emitted(23, 235) Source(49, 44) + SourceIndex(0) +18>Emitted(23, 246) Source(51, 22) + SourceIndex(0) +19>Emitted(23, 247) Source(51, 23) + SourceIndex(0) +20>Emitted(23, 250) Source(51, 26) + SourceIndex(0) +21>Emitted(23, 251) Source(51, 27) + SourceIndex(0) +22>Emitted(23, 253) Source(51, 29) + SourceIndex(0) +23>Emitted(23, 254) Source(51, 30) + SourceIndex(0) +24>Emitted(23, 257) Source(51, 33) + SourceIndex(0) +25>Emitted(23, 258) Source(51, 34) + SourceIndex(0) +26>Emitted(23, 260) Source(51, 36) + SourceIndex(0) +27>Emitted(23, 261) Source(51, 37) + SourceIndex(0) +28>Emitted(23, 263) Source(51, 39) + SourceIndex(0) +29>Emitted(23, 265) Source(51, 41) + SourceIndex(0) +30>Emitted(23, 266) Source(51, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -878,31 +884,31 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(25, 1) Source(53, 1) + SourceIndex(0) 2 >Emitted(25, 2) Source(53, 2) + SourceIndex(0) --- ->>>for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q, +>>>for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q), _q, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -915,41 +921,41 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary: primaryA = "primary" -12> -13> primary: primaryA = "primary" -14> , - > -15> secondary: secondaryA = "secondary" -16> -17> secondary: secondaryA = "secondary" +7 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary: primaryA = "primary" +12> +13> primary: primaryA = "primary" +14> , + > +15> secondary: secondaryA = "secondary" +16> +17> secondary: secondaryA = "secondary" 1->Emitted(26, 1) Source(54, 1) + SourceIndex(0) 2 >Emitted(26, 4) Source(54, 4) + SourceIndex(0) 3 >Emitted(26, 5) Source(54, 5) + SourceIndex(0) 4 >Emitted(26, 6) Source(54, 6) + SourceIndex(0) 5 >Emitted(26, 84) Source(59, 90) + SourceIndex(0) -6 >Emitted(26, 86) Source(55, 5) + SourceIndex(0) -7 >Emitted(26, 100) Source(58, 47) + SourceIndex(0) -8 >Emitted(26, 102) Source(55, 5) + SourceIndex(0) -9 >Emitted(26, 166) Source(58, 47) + SourceIndex(0) -10>Emitted(26, 168) Source(56, 9) + SourceIndex(0) -11>Emitted(26, 183) Source(56, 38) + SourceIndex(0) -12>Emitted(26, 185) Source(56, 9) + SourceIndex(0) -13>Emitted(26, 226) Source(56, 38) + SourceIndex(0) -14>Emitted(26, 228) Source(57, 9) + SourceIndex(0) -15>Emitted(26, 245) Source(57, 44) + SourceIndex(0) -16>Emitted(26, 247) Source(57, 9) + SourceIndex(0) -17>Emitted(26, 292) Source(57, 44) + SourceIndex(0) +6 >Emitted(26, 87) Source(55, 5) + SourceIndex(0) +7 >Emitted(26, 101) Source(58, 47) + SourceIndex(0) +8 >Emitted(26, 103) Source(55, 5) + SourceIndex(0) +9 >Emitted(26, 167) Source(58, 47) + SourceIndex(0) +10>Emitted(26, 169) Source(56, 9) + SourceIndex(0) +11>Emitted(26, 184) Source(56, 38) + SourceIndex(0) +12>Emitted(26, 186) Source(56, 9) + SourceIndex(0) +13>Emitted(26, 227) Source(56, 38) + SourceIndex(0) +14>Emitted(26, 229) Source(57, 9) + SourceIndex(0) +15>Emitted(26, 246) Source(57, 44) + SourceIndex(0) +16>Emitted(26, 248) Source(57, 9) + SourceIndex(0) +17>Emitted(26, 293) Source(57, 44) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -1345,14 +1351,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(38, 1) Source(72, 1) + SourceIndex(0) 2 >Emitted(38, 2) Source(72, 2) + SourceIndex(0) --- ->>>for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, i = 0; i < 1; i++) { +>>>for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -1371,18 +1377,20 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 16> ^^ 17> ^^^^^^^^^^ 18> ^^ -19> ^ -20> ^^^ -21> ^ -22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^ -29> ^^ -30> ^ +19> ^^^^^^^^^^ +20> ^^ +21> ^ +22> ^^^ +23> ^ +24> ^^ +25> ^ +26> ^^^ +27> ^ +28> ^^ +29> ^ +30> ^^ +31> ^^ +32> ^ 1-> > 2 >for @@ -1411,19 +1419,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 17> multiRobot -18> , -19> i -20> = -21> 0 -22> ; -23> i -24> < -25> 1 -26> ; -27> i -28> ++ -29> ) -30> { +18> +19> multiRobot +20> , +21> i +22> = +23> 0 +24> ; +25> i +26> < +27> 1 +28> ; +29> i +30> ++ +31> ) +32> { 1->Emitted(39, 1) Source(73, 1) + SourceIndex(0) 2 >Emitted(39, 4) Source(73, 4) + SourceIndex(0) 3 >Emitted(39, 5) Source(73, 5) + SourceIndex(0) @@ -1441,19 +1451,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 15>Emitted(39, 218) Source(76, 32) + SourceIndex(0) 16>Emitted(39, 220) Source(78, 5) + SourceIndex(0) 17>Emitted(39, 230) Source(78, 15) + SourceIndex(0) -18>Emitted(39, 232) Source(78, 17) + SourceIndex(0) -19>Emitted(39, 233) Source(78, 18) + SourceIndex(0) -20>Emitted(39, 236) Source(78, 21) + SourceIndex(0) -21>Emitted(39, 237) Source(78, 22) + SourceIndex(0) -22>Emitted(39, 239) Source(78, 24) + SourceIndex(0) -23>Emitted(39, 240) Source(78, 25) + SourceIndex(0) -24>Emitted(39, 243) Source(78, 28) + SourceIndex(0) -25>Emitted(39, 244) Source(78, 29) + SourceIndex(0) -26>Emitted(39, 246) Source(78, 31) + SourceIndex(0) -27>Emitted(39, 247) Source(78, 32) + SourceIndex(0) -28>Emitted(39, 249) Source(78, 34) + SourceIndex(0) -29>Emitted(39, 251) Source(78, 36) + SourceIndex(0) -30>Emitted(39, 252) Source(78, 37) + SourceIndex(0) +18>Emitted(39, 232) Source(78, 5) + SourceIndex(0) +19>Emitted(39, 242) Source(78, 15) + SourceIndex(0) +20>Emitted(39, 244) Source(78, 17) + SourceIndex(0) +21>Emitted(39, 245) Source(78, 18) + SourceIndex(0) +22>Emitted(39, 248) Source(78, 21) + SourceIndex(0) +23>Emitted(39, 249) Source(78, 22) + SourceIndex(0) +24>Emitted(39, 251) Source(78, 24) + SourceIndex(0) +25>Emitted(39, 252) Source(78, 25) + SourceIndex(0) +26>Emitted(39, 255) Source(78, 28) + SourceIndex(0) +27>Emitted(39, 256) Source(78, 29) + SourceIndex(0) +28>Emitted(39, 258) Source(78, 31) + SourceIndex(0) +29>Emitted(39, 259) Source(78, 32) + SourceIndex(0) +30>Emitted(39, 261) Source(78, 34) + SourceIndex(0) +31>Emitted(39, 263) Source(78, 36) + SourceIndex(0) +32>Emitted(39, 264) Source(78, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -1485,44 +1497,44 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(41, 1) Source(80, 1) + SourceIndex(0) 2 >Emitted(41, 2) Source(80, 2) + SourceIndex(0) --- ->>>for (_4 = getMultiRobot(), _5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4, i = 0; i < 1; i++) { +>>>for (_4 = getMultiRobot(), (_5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4), _4, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^^^^^ -19> ^ -20> ^^^ -21> ^ -22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^ -29> ^^ -30> ^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^^^^^^^^^^ +19> ^ +20> ^^^ +21> ^ +22> ^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^ +29> ^^ +30> ^ 1-> > 2 >for @@ -1535,69 +1547,69 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary = "primary" -12> -13> primary = "primary" -14> , - > -15> secondary = "secondary" -16> -17> secondary = "secondary" -18> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -19> i -20> = -21> 0 -22> ; -23> i -24> < -25> 1 -26> ; -27> i -28> ++ -29> ) -30> { +7 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary = "primary" +12> +13> primary = "primary" +14> , + > +15> secondary = "secondary" +16> +17> secondary = "secondary" +18> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +19> i +20> = +21> 0 +22> ; +23> i +24> < +25> 1 +26> ; +27> i +28> ++ +29> ) +30> { 1->Emitted(42, 1) Source(81, 1) + SourceIndex(0) 2 >Emitted(42, 4) Source(81, 4) + SourceIndex(0) 3 >Emitted(42, 5) Source(81, 5) + SourceIndex(0) 4 >Emitted(42, 6) Source(81, 6) + SourceIndex(0) 5 >Emitted(42, 26) Source(86, 20) + SourceIndex(0) -6 >Emitted(42, 28) Source(82, 5) + SourceIndex(0) -7 >Emitted(42, 42) Source(85, 47) + SourceIndex(0) -8 >Emitted(42, 44) Source(82, 5) + SourceIndex(0) -9 >Emitted(42, 108) Source(85, 47) + SourceIndex(0) -10>Emitted(42, 110) Source(83, 9) + SourceIndex(0) -11>Emitted(42, 125) Source(83, 28) + SourceIndex(0) -12>Emitted(42, 127) Source(83, 9) + SourceIndex(0) -13>Emitted(42, 167) Source(83, 28) + SourceIndex(0) -14>Emitted(42, 169) Source(84, 9) + SourceIndex(0) -15>Emitted(42, 186) Source(84, 32) + SourceIndex(0) -16>Emitted(42, 188) Source(84, 9) + SourceIndex(0) -17>Emitted(42, 232) Source(84, 32) + SourceIndex(0) -18>Emitted(42, 238) Source(86, 22) + SourceIndex(0) -19>Emitted(42, 239) Source(86, 23) + SourceIndex(0) -20>Emitted(42, 242) Source(86, 26) + SourceIndex(0) -21>Emitted(42, 243) Source(86, 27) + SourceIndex(0) -22>Emitted(42, 245) Source(86, 29) + SourceIndex(0) -23>Emitted(42, 246) Source(86, 30) + SourceIndex(0) -24>Emitted(42, 249) Source(86, 33) + SourceIndex(0) -25>Emitted(42, 250) Source(86, 34) + SourceIndex(0) -26>Emitted(42, 252) Source(86, 36) + SourceIndex(0) -27>Emitted(42, 253) Source(86, 37) + SourceIndex(0) -28>Emitted(42, 255) Source(86, 39) + SourceIndex(0) -29>Emitted(42, 257) Source(86, 41) + SourceIndex(0) -30>Emitted(42, 258) Source(86, 42) + SourceIndex(0) +6 >Emitted(42, 29) Source(82, 5) + SourceIndex(0) +7 >Emitted(42, 43) Source(85, 47) + SourceIndex(0) +8 >Emitted(42, 45) Source(82, 5) + SourceIndex(0) +9 >Emitted(42, 109) Source(85, 47) + SourceIndex(0) +10>Emitted(42, 111) Source(83, 9) + SourceIndex(0) +11>Emitted(42, 126) Source(83, 28) + SourceIndex(0) +12>Emitted(42, 128) Source(83, 9) + SourceIndex(0) +13>Emitted(42, 168) Source(83, 28) + SourceIndex(0) +14>Emitted(42, 170) Source(84, 9) + SourceIndex(0) +15>Emitted(42, 187) Source(84, 32) + SourceIndex(0) +16>Emitted(42, 189) Source(84, 9) + SourceIndex(0) +17>Emitted(42, 233) Source(84, 32) + SourceIndex(0) +18>Emitted(42, 244) Source(86, 22) + SourceIndex(0) +19>Emitted(42, 245) Source(86, 23) + SourceIndex(0) +20>Emitted(42, 248) Source(86, 26) + SourceIndex(0) +21>Emitted(42, 249) Source(86, 27) + SourceIndex(0) +22>Emitted(42, 251) Source(86, 29) + SourceIndex(0) +23>Emitted(42, 252) Source(86, 30) + SourceIndex(0) +24>Emitted(42, 255) Source(86, 33) + SourceIndex(0) +25>Emitted(42, 256) Source(86, 34) + SourceIndex(0) +26>Emitted(42, 258) Source(86, 36) + SourceIndex(0) +27>Emitted(42, 259) Source(86, 37) + SourceIndex(0) +28>Emitted(42, 261) Source(86, 39) + SourceIndex(0) +29>Emitted(42, 263) Source(86, 41) + SourceIndex(0) +30>Emitted(42, 264) Source(86, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -1629,31 +1641,31 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(44, 1) Source(88, 1) + SourceIndex(0) 2 >Emitted(44, 2) Source(88, 2) + SourceIndex(0) --- ->>>for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9, +>>>for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9), _9, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -1666,41 +1678,41 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -8 > -9 > skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -10> -11> primary = "primary" -12> -13> primary = "primary" -14> , - > -15> secondary = "secondary" -16> -17> secondary = "secondary" +7 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +8 > +9 > skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +10> +11> primary = "primary" +12> +13> primary = "primary" +14> , + > +15> secondary = "secondary" +16> +17> secondary = "secondary" 1->Emitted(45, 1) Source(89, 1) + SourceIndex(0) 2 >Emitted(45, 4) Source(89, 4) + SourceIndex(0) 3 >Emitted(45, 5) Source(89, 5) + SourceIndex(0) 4 >Emitted(45, 6) Source(89, 6) + SourceIndex(0) 5 >Emitted(45, 84) Source(94, 90) + SourceIndex(0) -6 >Emitted(45, 86) Source(90, 5) + SourceIndex(0) -7 >Emitted(45, 101) Source(93, 47) + SourceIndex(0) -8 >Emitted(45, 103) Source(90, 5) + SourceIndex(0) -9 >Emitted(45, 170) Source(93, 47) + SourceIndex(0) -10>Emitted(45, 172) Source(91, 9) + SourceIndex(0) -11>Emitted(45, 189) Source(91, 28) + SourceIndex(0) -12>Emitted(45, 191) Source(91, 9) + SourceIndex(0) -13>Emitted(45, 233) Source(91, 28) + SourceIndex(0) -14>Emitted(45, 235) Source(92, 9) + SourceIndex(0) -15>Emitted(45, 254) Source(92, 32) + SourceIndex(0) -16>Emitted(45, 256) Source(92, 9) + SourceIndex(0) -17>Emitted(45, 302) Source(92, 32) + SourceIndex(0) +6 >Emitted(45, 87) Source(90, 5) + SourceIndex(0) +7 >Emitted(45, 102) Source(93, 47) + SourceIndex(0) +8 >Emitted(45, 104) Source(90, 5) + SourceIndex(0) +9 >Emitted(45, 171) Source(93, 47) + SourceIndex(0) +10>Emitted(45, 173) Source(91, 9) + SourceIndex(0) +11>Emitted(45, 190) Source(91, 28) + SourceIndex(0) +12>Emitted(45, 192) Source(91, 9) + SourceIndex(0) +13>Emitted(45, 234) Source(91, 28) + SourceIndex(0) +14>Emitted(45, 236) Source(92, 9) + SourceIndex(0) +15>Emitted(45, 255) Source(92, 32) + SourceIndex(0) +16>Emitted(45, 257) Source(92, 9) + SourceIndex(0) +17>Emitted(45, 303) Source(92, 32) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -2133,14 +2145,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(57, 1) Source(108, 1) + SourceIndex(0) 2 >Emitted(57, 2) Source(108, 2) + SourceIndex(0) --- ->>>for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, i = 0; i < 1; i++) { +>>>for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -2163,18 +2175,20 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 20> ^^ 21> ^^^^^^^^^^ 22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^^ -29> ^ -30> ^^ -31> ^ -32> ^^ -33> ^^ -34> ^ +23> ^^^^^^^^^^ +24> ^^ +25> ^ +26> ^^^ +27> ^ +28> ^^ +29> ^ +30> ^^^ +31> ^ +32> ^^ +33> ^ +34> ^^ +35> ^^ +36> ^ 1-> > 2 >for @@ -2208,19 +2222,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 21> multiRobot -22> , -23> i -24> = -25> 0 -26> ; -27> i -28> < -29> 1 -30> ; -31> i -32> ++ -33> ) -34> { +22> +23> multiRobot +24> , +25> i +26> = +27> 0 +28> ; +29> i +30> < +31> 1 +32> ; +33> i +34> ++ +35> ) +36> { 1->Emitted(58, 1) Source(109, 1) + SourceIndex(0) 2 >Emitted(58, 4) Source(109, 4) + SourceIndex(0) 3 >Emitted(58, 5) Source(109, 5) + SourceIndex(0) @@ -2242,19 +2258,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 19>Emitted(58, 296) Source(113, 44) + SourceIndex(0) 20>Emitted(58, 298) Source(115, 5) + SourceIndex(0) 21>Emitted(58, 308) Source(115, 15) + SourceIndex(0) -22>Emitted(58, 310) Source(115, 17) + SourceIndex(0) -23>Emitted(58, 311) Source(115, 18) + SourceIndex(0) -24>Emitted(58, 314) Source(115, 21) + SourceIndex(0) -25>Emitted(58, 315) Source(115, 22) + SourceIndex(0) -26>Emitted(58, 317) Source(115, 24) + SourceIndex(0) -27>Emitted(58, 318) Source(115, 25) + SourceIndex(0) -28>Emitted(58, 321) Source(115, 28) + SourceIndex(0) -29>Emitted(58, 322) Source(115, 29) + SourceIndex(0) -30>Emitted(58, 324) Source(115, 31) + SourceIndex(0) -31>Emitted(58, 325) Source(115, 32) + SourceIndex(0) -32>Emitted(58, 327) Source(115, 34) + SourceIndex(0) -33>Emitted(58, 329) Source(115, 36) + SourceIndex(0) -34>Emitted(58, 330) Source(115, 37) + SourceIndex(0) +22>Emitted(58, 310) Source(115, 5) + SourceIndex(0) +23>Emitted(58, 320) Source(115, 15) + SourceIndex(0) +24>Emitted(58, 322) Source(115, 17) + SourceIndex(0) +25>Emitted(58, 323) Source(115, 18) + SourceIndex(0) +26>Emitted(58, 326) Source(115, 21) + SourceIndex(0) +27>Emitted(58, 327) Source(115, 22) + SourceIndex(0) +28>Emitted(58, 329) Source(115, 24) + SourceIndex(0) +29>Emitted(58, 330) Source(115, 25) + SourceIndex(0) +30>Emitted(58, 333) Source(115, 28) + SourceIndex(0) +31>Emitted(58, 334) Source(115, 29) + SourceIndex(0) +32>Emitted(58, 336) Source(115, 31) + SourceIndex(0) +33>Emitted(58, 337) Source(115, 32) + SourceIndex(0) +34>Emitted(58, 339) Source(115, 34) + SourceIndex(0) +35>Emitted(58, 341) Source(115, 36) + SourceIndex(0) +36>Emitted(58, 342) Source(115, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -2286,48 +2304,48 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(60, 1) Source(117, 1) + SourceIndex(0) 2 >Emitted(60, 2) Source(117, 2) + SourceIndex(0) --- ->>>for (_27 = getMultiRobot(), _28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27, i = 0; i < 1; i++) { +>>>for (_27 = getMultiRobot(), (_28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27), _27, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -22> ^^^^^^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^^ -29> ^ -30> ^^ -31> ^ -32> ^^ -33> ^^ -34> ^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +22> ^^^^^^^^^^^^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^^ +29> ^ +30> ^^ +31> ^ +32> ^^ +33> ^^ +34> ^ 1-> > 2 >for @@ -2341,78 +2359,78 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > name: nameA = "noName" -8 > -9 > name: nameA = "noName" -10> , - > -11> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary: primaryA = "primary" -16> -17> primary: primaryA = "primary" -18> , - > -19> secondary: secondaryA = "secondary" -20> -21> secondary: secondaryA = "secondary" -22> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -23> i -24> = -25> 0 -26> ; -27> i -28> < -29> 1 -30> ; -31> i -32> ++ -33> ) -34> { +7 > name: nameA = "noName" +8 > +9 > name: nameA = "noName" +10> , + > +11> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary: primaryA = "primary" +16> +17> primary: primaryA = "primary" +18> , + > +19> secondary: secondaryA = "secondary" +20> +21> secondary: secondaryA = "secondary" +22> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +23> i +24> = +25> 0 +26> ; +27> i +28> < +29> 1 +30> ; +31> i +32> ++ +33> ) +34> { 1->Emitted(61, 1) Source(118, 1) + SourceIndex(0) 2 >Emitted(61, 4) Source(118, 4) + SourceIndex(0) 3 >Emitted(61, 5) Source(118, 5) + SourceIndex(0) 4 >Emitted(61, 6) Source(118, 6) + SourceIndex(0) 5 >Emitted(61, 27) Source(124, 20) + SourceIndex(0) -6 >Emitted(61, 29) Source(119, 5) + SourceIndex(0) -7 >Emitted(61, 43) Source(119, 27) + SourceIndex(0) -8 >Emitted(61, 45) Source(119, 5) + SourceIndex(0) -9 >Emitted(61, 84) Source(119, 27) + SourceIndex(0) -10>Emitted(61, 86) Source(120, 5) + SourceIndex(0) -11>Emitted(61, 102) Source(123, 47) + SourceIndex(0) -12>Emitted(61, 104) Source(120, 5) + SourceIndex(0) -13>Emitted(61, 171) Source(123, 47) + SourceIndex(0) -14>Emitted(61, 173) Source(121, 9) + SourceIndex(0) -15>Emitted(61, 190) Source(121, 38) + SourceIndex(0) -16>Emitted(61, 192) Source(121, 9) + SourceIndex(0) -17>Emitted(61, 235) Source(121, 38) + SourceIndex(0) -18>Emitted(61, 237) Source(122, 9) + SourceIndex(0) -19>Emitted(61, 256) Source(122, 44) + SourceIndex(0) -20>Emitted(61, 258) Source(122, 9) + SourceIndex(0) -21>Emitted(61, 305) Source(122, 44) + SourceIndex(0) -22>Emitted(61, 312) Source(124, 22) + SourceIndex(0) -23>Emitted(61, 313) Source(124, 23) + SourceIndex(0) -24>Emitted(61, 316) Source(124, 26) + SourceIndex(0) -25>Emitted(61, 317) Source(124, 27) + SourceIndex(0) -26>Emitted(61, 319) Source(124, 29) + SourceIndex(0) -27>Emitted(61, 320) Source(124, 30) + SourceIndex(0) -28>Emitted(61, 323) Source(124, 33) + SourceIndex(0) -29>Emitted(61, 324) Source(124, 34) + SourceIndex(0) -30>Emitted(61, 326) Source(124, 36) + SourceIndex(0) -31>Emitted(61, 327) Source(124, 37) + SourceIndex(0) -32>Emitted(61, 329) Source(124, 39) + SourceIndex(0) -33>Emitted(61, 331) Source(124, 41) + SourceIndex(0) -34>Emitted(61, 332) Source(124, 42) + SourceIndex(0) +6 >Emitted(61, 30) Source(119, 5) + SourceIndex(0) +7 >Emitted(61, 44) Source(119, 27) + SourceIndex(0) +8 >Emitted(61, 46) Source(119, 5) + SourceIndex(0) +9 >Emitted(61, 85) Source(119, 27) + SourceIndex(0) +10>Emitted(61, 87) Source(120, 5) + SourceIndex(0) +11>Emitted(61, 103) Source(123, 47) + SourceIndex(0) +12>Emitted(61, 105) Source(120, 5) + SourceIndex(0) +13>Emitted(61, 172) Source(123, 47) + SourceIndex(0) +14>Emitted(61, 174) Source(121, 9) + SourceIndex(0) +15>Emitted(61, 191) Source(121, 38) + SourceIndex(0) +16>Emitted(61, 193) Source(121, 9) + SourceIndex(0) +17>Emitted(61, 236) Source(121, 38) + SourceIndex(0) +18>Emitted(61, 238) Source(122, 9) + SourceIndex(0) +19>Emitted(61, 257) Source(122, 44) + SourceIndex(0) +20>Emitted(61, 259) Source(122, 9) + SourceIndex(0) +21>Emitted(61, 306) Source(122, 44) + SourceIndex(0) +22>Emitted(61, 319) Source(124, 22) + SourceIndex(0) +23>Emitted(61, 320) Source(124, 23) + SourceIndex(0) +24>Emitted(61, 323) Source(124, 26) + SourceIndex(0) +25>Emitted(61, 324) Source(124, 27) + SourceIndex(0) +26>Emitted(61, 326) Source(124, 29) + SourceIndex(0) +27>Emitted(61, 327) Source(124, 30) + SourceIndex(0) +28>Emitted(61, 330) Source(124, 33) + SourceIndex(0) +29>Emitted(61, 331) Source(124, 34) + SourceIndex(0) +30>Emitted(61, 333) Source(124, 36) + SourceIndex(0) +31>Emitted(61, 334) Source(124, 37) + SourceIndex(0) +32>Emitted(61, 336) Source(124, 39) + SourceIndex(0) +33>Emitted(61, 338) Source(124, 41) + SourceIndex(0) +34>Emitted(61, 339) Source(124, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -2444,35 +2462,35 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(63, 1) Source(126, 1) + SourceIndex(0) 2 >Emitted(63, 2) Source(126, 2) + SourceIndex(0) --- ->>>for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33, +>>>for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33), _33, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -2486,50 +2504,50 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > name: nameA = "noName" -8 > -9 > name: nameA = "noName" -10> , - > -11> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary: primaryA = "primary", - > secondary: secondaryA = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary: primaryA = "primary" -16> -17> primary: primaryA = "primary" -18> , - > -19> secondary: secondaryA = "secondary" -20> -21> secondary: secondaryA = "secondary" +7 > name: nameA = "noName" +8 > +9 > name: nameA = "noName" +10> , + > +11> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary: primaryA = "primary", + > secondary: secondaryA = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary: primaryA = "primary" +16> +17> primary: primaryA = "primary" +18> , + > +19> secondary: secondaryA = "secondary" +20> +21> secondary: secondaryA = "secondary" 1->Emitted(64, 1) Source(127, 1) + SourceIndex(0) 2 >Emitted(64, 4) Source(127, 4) + SourceIndex(0) 3 >Emitted(64, 5) Source(127, 5) + SourceIndex(0) 4 >Emitted(64, 6) Source(127, 6) + SourceIndex(0) 5 >Emitted(64, 85) Source(133, 90) + SourceIndex(0) -6 >Emitted(64, 87) Source(128, 5) + SourceIndex(0) -7 >Emitted(64, 101) Source(128, 27) + SourceIndex(0) -8 >Emitted(64, 103) Source(128, 5) + SourceIndex(0) -9 >Emitted(64, 142) Source(128, 27) + SourceIndex(0) -10>Emitted(64, 144) Source(129, 5) + SourceIndex(0) -11>Emitted(64, 160) Source(132, 47) + SourceIndex(0) -12>Emitted(64, 162) Source(129, 5) + SourceIndex(0) -13>Emitted(64, 229) Source(132, 47) + SourceIndex(0) -14>Emitted(64, 231) Source(130, 9) + SourceIndex(0) -15>Emitted(64, 248) Source(130, 38) + SourceIndex(0) -16>Emitted(64, 250) Source(130, 9) + SourceIndex(0) -17>Emitted(64, 293) Source(130, 38) + SourceIndex(0) -18>Emitted(64, 295) Source(131, 9) + SourceIndex(0) -19>Emitted(64, 314) Source(131, 44) + SourceIndex(0) -20>Emitted(64, 316) Source(131, 9) + SourceIndex(0) -21>Emitted(64, 363) Source(131, 44) + SourceIndex(0) +6 >Emitted(64, 88) Source(128, 5) + SourceIndex(0) +7 >Emitted(64, 102) Source(128, 27) + SourceIndex(0) +8 >Emitted(64, 104) Source(128, 5) + SourceIndex(0) +9 >Emitted(64, 143) Source(128, 27) + SourceIndex(0) +10>Emitted(64, 145) Source(129, 5) + SourceIndex(0) +11>Emitted(64, 161) Source(132, 47) + SourceIndex(0) +12>Emitted(64, 163) Source(129, 5) + SourceIndex(0) +13>Emitted(64, 230) Source(132, 47) + SourceIndex(0) +14>Emitted(64, 232) Source(130, 9) + SourceIndex(0) +15>Emitted(64, 249) Source(130, 38) + SourceIndex(0) +16>Emitted(64, 251) Source(130, 9) + SourceIndex(0) +17>Emitted(64, 294) Source(130, 38) + SourceIndex(0) +18>Emitted(64, 296) Source(131, 9) + SourceIndex(0) +19>Emitted(64, 315) Source(131, 44) + SourceIndex(0) +20>Emitted(64, 317) Source(131, 9) + SourceIndex(0) +21>Emitted(64, 364) Source(131, 44) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -2961,14 +2979,14 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(76, 1) Source(146, 1) + SourceIndex(0) 2 >Emitted(76, 2) Source(146, 2) + SourceIndex(0) --- ->>>for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, i = 0; i < 1; i++) { +>>>for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, multiRobot, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ @@ -2991,18 +3009,20 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 20> ^^ 21> ^^^^^^^^^^ 22> ^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^^ -29> ^ -30> ^^ -31> ^ -32> ^^ -33> ^^ -34> ^ +23> ^^^^^^^^^^ +24> ^^ +25> ^ +26> ^^^ +27> ^ +28> ^^ +29> ^ +30> ^^^ +31> ^ +32> ^^ +33> ^ +34> ^^ +35> ^^ +36> ^ 1-> > 2 >for @@ -3036,19 +3056,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = 21> multiRobot -22> , -23> i -24> = -25> 0 -26> ; -27> i -28> < -29> 1 -30> ; -31> i -32> ++ -33> ) -34> { +22> +23> multiRobot +24> , +25> i +26> = +27> 0 +28> ; +29> i +30> < +31> 1 +32> ; +33> i +34> ++ +35> ) +36> { 1->Emitted(77, 1) Source(147, 1) + SourceIndex(0) 2 >Emitted(77, 4) Source(147, 4) + SourceIndex(0) 3 >Emitted(77, 5) Source(147, 5) + SourceIndex(0) @@ -3070,19 +3092,21 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 19>Emitted(77, 293) Source(151, 32) + SourceIndex(0) 20>Emitted(77, 295) Source(153, 5) + SourceIndex(0) 21>Emitted(77, 305) Source(153, 15) + SourceIndex(0) -22>Emitted(77, 307) Source(153, 17) + SourceIndex(0) -23>Emitted(77, 308) Source(153, 18) + SourceIndex(0) -24>Emitted(77, 311) Source(153, 21) + SourceIndex(0) -25>Emitted(77, 312) Source(153, 22) + SourceIndex(0) -26>Emitted(77, 314) Source(153, 24) + SourceIndex(0) -27>Emitted(77, 315) Source(153, 25) + SourceIndex(0) -28>Emitted(77, 318) Source(153, 28) + SourceIndex(0) -29>Emitted(77, 319) Source(153, 29) + SourceIndex(0) -30>Emitted(77, 321) Source(153, 31) + SourceIndex(0) -31>Emitted(77, 322) Source(153, 32) + SourceIndex(0) -32>Emitted(77, 324) Source(153, 34) + SourceIndex(0) -33>Emitted(77, 326) Source(153, 36) + SourceIndex(0) -34>Emitted(77, 327) Source(153, 37) + SourceIndex(0) +22>Emitted(77, 307) Source(153, 5) + SourceIndex(0) +23>Emitted(77, 317) Source(153, 15) + SourceIndex(0) +24>Emitted(77, 319) Source(153, 17) + SourceIndex(0) +25>Emitted(77, 320) Source(153, 18) + SourceIndex(0) +26>Emitted(77, 323) Source(153, 21) + SourceIndex(0) +27>Emitted(77, 324) Source(153, 22) + SourceIndex(0) +28>Emitted(77, 326) Source(153, 24) + SourceIndex(0) +29>Emitted(77, 327) Source(153, 25) + SourceIndex(0) +30>Emitted(77, 330) Source(153, 28) + SourceIndex(0) +31>Emitted(77, 331) Source(153, 29) + SourceIndex(0) +32>Emitted(77, 333) Source(153, 31) + SourceIndex(0) +33>Emitted(77, 334) Source(153, 32) + SourceIndex(0) +34>Emitted(77, 336) Source(153, 34) + SourceIndex(0) +35>Emitted(77, 338) Source(153, 36) + SourceIndex(0) +36>Emitted(77, 339) Source(153, 37) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -3114,48 +3138,48 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(79, 1) Source(155, 1) + SourceIndex(0) 2 >Emitted(79, 2) Source(155, 2) + SourceIndex(0) --- ->>>for (_52 = getMultiRobot(), _53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52, i = 0; i < 1; i++) { +>>>for (_52 = getMultiRobot(), (_53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52), _52, i = 0; i < 1; i++) { 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -22> ^^^^^^^ -23> ^ -24> ^^^ -25> ^ -26> ^^ -27> ^ -28> ^^^ -29> ^ -30> ^^ -31> ^ -32> ^^ -33> ^^ -34> ^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +22> ^^^^^^^^^^^^^ +23> ^ +24> ^^^ +25> ^ +26> ^^ +27> ^ +28> ^^^ +29> ^ +30> ^^ +31> ^ +32> ^^ +33> ^^ +34> ^ 1-> > 2 >for @@ -3169,78 +3193,78 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = getMultiRobot() 6 > -7 > name = "noName" -8 > -9 > name = "noName" -10> , - > -11> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary = "primary" -16> -17> primary = "primary" -18> , - > -19> secondary = "secondary" -20> -21> secondary = "secondary" -22> - > } = { primary: "none", secondary: "none" } - > } = getMultiRobot(), -23> i -24> = -25> 0 -26> ; -27> i -28> < -29> 1 -30> ; -31> i -32> ++ -33> ) -34> { +7 > name = "noName" +8 > +9 > name = "noName" +10> , + > +11> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary = "primary" +16> +17> primary = "primary" +18> , + > +19> secondary = "secondary" +20> +21> secondary = "secondary" +22> + > } = { primary: "none", secondary: "none" } + > } = getMultiRobot(), +23> i +24> = +25> 0 +26> ; +27> i +28> < +29> 1 +30> ; +31> i +32> ++ +33> ) +34> { 1->Emitted(80, 1) Source(156, 1) + SourceIndex(0) 2 >Emitted(80, 4) Source(156, 4) + SourceIndex(0) 3 >Emitted(80, 5) Source(156, 5) + SourceIndex(0) 4 >Emitted(80, 6) Source(156, 6) + SourceIndex(0) 5 >Emitted(80, 27) Source(162, 20) + SourceIndex(0) -6 >Emitted(80, 29) Source(157, 5) + SourceIndex(0) -7 >Emitted(80, 43) Source(157, 20) + SourceIndex(0) -8 >Emitted(80, 45) Source(157, 5) + SourceIndex(0) -9 >Emitted(80, 83) Source(157, 20) + SourceIndex(0) -10>Emitted(80, 85) Source(158, 5) + SourceIndex(0) -11>Emitted(80, 101) Source(161, 47) + SourceIndex(0) -12>Emitted(80, 103) Source(158, 5) + SourceIndex(0) -13>Emitted(80, 170) Source(161, 47) + SourceIndex(0) -14>Emitted(80, 172) Source(159, 9) + SourceIndex(0) -15>Emitted(80, 189) Source(159, 28) + SourceIndex(0) -16>Emitted(80, 191) Source(159, 9) + SourceIndex(0) -17>Emitted(80, 233) Source(159, 28) + SourceIndex(0) -18>Emitted(80, 235) Source(160, 9) + SourceIndex(0) -19>Emitted(80, 254) Source(160, 32) + SourceIndex(0) -20>Emitted(80, 256) Source(160, 9) + SourceIndex(0) -21>Emitted(80, 302) Source(160, 32) + SourceIndex(0) -22>Emitted(80, 309) Source(162, 22) + SourceIndex(0) -23>Emitted(80, 310) Source(162, 23) + SourceIndex(0) -24>Emitted(80, 313) Source(162, 26) + SourceIndex(0) -25>Emitted(80, 314) Source(162, 27) + SourceIndex(0) -26>Emitted(80, 316) Source(162, 29) + SourceIndex(0) -27>Emitted(80, 317) Source(162, 30) + SourceIndex(0) -28>Emitted(80, 320) Source(162, 33) + SourceIndex(0) -29>Emitted(80, 321) Source(162, 34) + SourceIndex(0) -30>Emitted(80, 323) Source(162, 36) + SourceIndex(0) -31>Emitted(80, 324) Source(162, 37) + SourceIndex(0) -32>Emitted(80, 326) Source(162, 39) + SourceIndex(0) -33>Emitted(80, 328) Source(162, 41) + SourceIndex(0) -34>Emitted(80, 329) Source(162, 42) + SourceIndex(0) +6 >Emitted(80, 30) Source(157, 5) + SourceIndex(0) +7 >Emitted(80, 44) Source(157, 20) + SourceIndex(0) +8 >Emitted(80, 46) Source(157, 5) + SourceIndex(0) +9 >Emitted(80, 84) Source(157, 20) + SourceIndex(0) +10>Emitted(80, 86) Source(158, 5) + SourceIndex(0) +11>Emitted(80, 102) Source(161, 47) + SourceIndex(0) +12>Emitted(80, 104) Source(158, 5) + SourceIndex(0) +13>Emitted(80, 171) Source(161, 47) + SourceIndex(0) +14>Emitted(80, 173) Source(159, 9) + SourceIndex(0) +15>Emitted(80, 190) Source(159, 28) + SourceIndex(0) +16>Emitted(80, 192) Source(159, 9) + SourceIndex(0) +17>Emitted(80, 234) Source(159, 28) + SourceIndex(0) +18>Emitted(80, 236) Source(160, 9) + SourceIndex(0) +19>Emitted(80, 255) Source(160, 32) + SourceIndex(0) +20>Emitted(80, 257) Source(160, 9) + SourceIndex(0) +21>Emitted(80, 303) Source(160, 32) + SourceIndex(0) +22>Emitted(80, 316) Source(162, 22) + SourceIndex(0) +23>Emitted(80, 317) Source(162, 23) + SourceIndex(0) +24>Emitted(80, 320) Source(162, 26) + SourceIndex(0) +25>Emitted(80, 321) Source(162, 27) + SourceIndex(0) +26>Emitted(80, 323) Source(162, 29) + SourceIndex(0) +27>Emitted(80, 324) Source(162, 30) + SourceIndex(0) +28>Emitted(80, 327) Source(162, 33) + SourceIndex(0) +29>Emitted(80, 328) Source(162, 34) + SourceIndex(0) +30>Emitted(80, 330) Source(162, 36) + SourceIndex(0) +31>Emitted(80, 331) Source(162, 37) + SourceIndex(0) +32>Emitted(80, 333) Source(162, 39) + SourceIndex(0) +33>Emitted(80, 335) Source(162, 41) + SourceIndex(0) +34>Emitted(80, 336) Source(162, 42) + SourceIndex(0) --- >>> console.log(primaryA); 1 >^^^^ @@ -3272,35 +3296,35 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(82, 1) Source(164, 1) + SourceIndex(0) 2 >Emitted(82, 2) Source(164, 2) + SourceIndex(0) --- ->>>for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58, +>>>for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58), _58, 1-> 2 >^^^ 3 > ^ 4 > ^ 5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -6 > ^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^ -9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -10> ^^ -11> ^^^^^^^^^^^^^^^^ -12> ^^ -13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -14> ^^ -15> ^^^^^^^^^^^^^^^^^ -16> ^^ -17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -18> ^^ -19> ^^^^^^^^^^^^^^^^^^^ -20> ^^ -21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +6 > ^^^ +7 > ^^^^^^^^^^^^^^ +8 > ^^ +9 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +10> ^^ +11> ^^^^^^^^^^^^^^^^ +12> ^^ +13> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +14> ^^ +15> ^^^^^^^^^^^^^^^^^ +16> ^^ +17> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +18> ^^ +19> ^^^^^^^^^^^^^^^^^^^ +20> ^^ +21> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> > 2 >for @@ -3314,50 +3338,50 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 > } = { primary: "none", secondary: "none" } > } = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } } 6 > -7 > name = "noName" -8 > -9 > name = "noName" -10> , - > -11> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -12> -13> skills: { - > primary = "primary", - > secondary = "secondary" - > } = { primary: "none", secondary: "none" } -14> -15> primary = "primary" -16> -17> primary = "primary" -18> , - > -19> secondary = "secondary" -20> -21> secondary = "secondary" +7 > name = "noName" +8 > +9 > name = "noName" +10> , + > +11> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +12> +13> skills: { + > primary = "primary", + > secondary = "secondary" + > } = { primary: "none", secondary: "none" } +14> +15> primary = "primary" +16> +17> primary = "primary" +18> , + > +19> secondary = "secondary" +20> +21> secondary = "secondary" 1->Emitted(83, 1) Source(165, 1) + SourceIndex(0) 2 >Emitted(83, 4) Source(165, 4) + SourceIndex(0) 3 >Emitted(83, 5) Source(165, 5) + SourceIndex(0) 4 >Emitted(83, 6) Source(165, 6) + SourceIndex(0) 5 >Emitted(83, 85) Source(171, 90) + SourceIndex(0) -6 >Emitted(83, 87) Source(166, 5) + SourceIndex(0) -7 >Emitted(83, 101) Source(166, 20) + SourceIndex(0) -8 >Emitted(83, 103) Source(166, 5) + SourceIndex(0) -9 >Emitted(83, 141) Source(166, 20) + SourceIndex(0) -10>Emitted(83, 143) Source(167, 5) + SourceIndex(0) -11>Emitted(83, 159) Source(170, 47) + SourceIndex(0) -12>Emitted(83, 161) Source(167, 5) + SourceIndex(0) -13>Emitted(83, 228) Source(170, 47) + SourceIndex(0) -14>Emitted(83, 230) Source(168, 9) + SourceIndex(0) -15>Emitted(83, 247) Source(168, 28) + SourceIndex(0) -16>Emitted(83, 249) Source(168, 9) + SourceIndex(0) -17>Emitted(83, 291) Source(168, 28) + SourceIndex(0) -18>Emitted(83, 293) Source(169, 9) + SourceIndex(0) -19>Emitted(83, 312) Source(169, 32) + SourceIndex(0) -20>Emitted(83, 314) Source(169, 9) + SourceIndex(0) -21>Emitted(83, 360) Source(169, 32) + SourceIndex(0) +6 >Emitted(83, 88) Source(166, 5) + SourceIndex(0) +7 >Emitted(83, 102) Source(166, 20) + SourceIndex(0) +8 >Emitted(83, 104) Source(166, 5) + SourceIndex(0) +9 >Emitted(83, 142) Source(166, 20) + SourceIndex(0) +10>Emitted(83, 144) Source(167, 5) + SourceIndex(0) +11>Emitted(83, 160) Source(170, 47) + SourceIndex(0) +12>Emitted(83, 162) Source(167, 5) + SourceIndex(0) +13>Emitted(83, 229) Source(170, 47) + SourceIndex(0) +14>Emitted(83, 231) Source(168, 9) + SourceIndex(0) +15>Emitted(83, 248) Source(168, 28) + SourceIndex(0) +16>Emitted(83, 250) Source(168, 9) + SourceIndex(0) +17>Emitted(83, 292) Source(168, 28) + SourceIndex(0) +18>Emitted(83, 294) Source(169, 9) + SourceIndex(0) +19>Emitted(83, 313) Source(169, 32) + SourceIndex(0) +20>Emitted(83, 315) Source(169, 9) + SourceIndex(0) +21>Emitted(83, 361) Source(169, 32) + SourceIndex(0) --- >>> i = 0; i < 1; i++) { 1 >^^^^ @@ -3434,12 +3458,13 @@ sourceFile:sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2 >>>} 1 > 2 >^ -3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > 2 >} 1 >Emitted(86, 1) Source(174, 1) + SourceIndex(0) 2 >Emitted(86, 2) Source(174, 2) + SourceIndex(0) --- ->>>var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63; +>>>var _k, _q, _4, _9, _27, _33, _52, _58; +>>>var _a, _b, _c, _d, _e, _f, _g, _h, _j, _l, _m, _o, _p, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _5, _6, _7, _8, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _28, _29, _30, _31, _32, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _53, _54, _55, _56, _57, _59, _60, _61, _62, _63; >>>//# sourceMappingURL=sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map \ No newline at end of file From 334820c357c50f9926ea4c4cbd09f9673755cf65 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 16:26:34 -0700 Subject: [PATCH 61/85] Remove spread types, leaving spread syntax/emit Spreads are still typed, but cannot be created from a non-object type. Tests still need to be updated. --- src/compiler/checker.ts | 343 ++++----------------------- src/compiler/declarationEmitter.ts | 9 - src/compiler/diagnosticMessages.json | 6 +- src/compiler/parser.ts | 17 -- src/compiler/types.ts | 22 +- src/lib/es2015.core.d.ts | 6 +- 6 files changed, 53 insertions(+), 350 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5447e652f08fe..c6924e2cb0aa8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -113,7 +113,6 @@ namespace ts { const tupleTypes: GenericType[] = []; const unionTypes = createMap(); const intersectionTypes = createMap(); - const spreadTypes = createMap(); const stringLiteralTypes = createMap(); const numericLiteralTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; @@ -2244,9 +2243,6 @@ namespace ts { else if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, nextFlags); } - else if (type.flags & TypeFlags.Spread) { - writeSpreadType(type); - } else if (getObjectFlags(type) & ObjectFlags.Anonymous) { writeAnonymousType(type, nextFlags); } @@ -2362,48 +2358,6 @@ namespace ts { } } - function writeSpreadType(type: SpreadType) { - writePunctuation(writer, SyntaxKind.OpenBraceToken); - writer.writeLine(); - writer.increaseIndent(); - - writeSpreadTypeWorker(type, /*atEnd*/true, type.symbol); - - writer.decreaseIndent(); - writePunctuation(writer, SyntaxKind.CloseBraceToken); - } - - function writeSpreadTypeWorker(type: SpreadType, atEnd: boolean, container: Symbol): void { - if (type.left.flags & TypeFlags.Spread) { - writeSpreadTypeWorker(type.left as SpreadType, /*atEnd*/false, container); - } - else { - const saveInObjectTypeLiteral = inObjectTypeLiteral; - inObjectTypeLiteral = true; - writeObjectLiteralType(resolveStructuredTypeMembers(type.left as ResolvedType)); - inObjectTypeLiteral = saveInObjectTypeLiteral; - } - if (type.right.symbol === container) { - // if type.right was written as part of the spread type, don't surround with ...{ }. - // this gives { a: number, ... T } instead of { ...{ a: number }, ...T } - const saveInObjectTypeLiteral = inObjectTypeLiteral; - inObjectTypeLiteral = true; - writeObjectLiteralType(resolveStructuredTypeMembers(type.right as ResolvedType)); - inObjectTypeLiteral = saveInObjectTypeLiteral; - } - else { - writePunctuation(writer, SyntaxKind.DotDotDotToken); - writeType(type.right, TypeFormatFlags.None); - if (atEnd) { - writeSpace(writer); - } - else { - writePunctuation(writer, SyntaxKind.SemicolonToken); - writer.writeLine(); - } - } - } - function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) { const symbol = type.symbol; if (symbol) { @@ -3623,7 +3577,6 @@ namespace ts { links.type = getUnionType([getTypeOfSymbol(links.leftSpread), getTypeOfSymbol(links.rightSpread)]); } return links.type; - } function getTargetType(type: Type): Type { @@ -4567,10 +4520,6 @@ namespace ts { return type.resolvedApparentType; } - function getApparentTypeOfSpread(type: SpreadType) { - return getApparentType(type.right); - } - /** * For a type parameter, return the base constraint of the type parameter. For the string, number, * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the @@ -4578,7 +4527,6 @@ namespace ts { */ function getApparentType(type: Type): Type { let t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(type) : type; - t = t.flags & TypeFlags.Spread ? getApparentTypeOfSpread(type as SpreadType) : t; return t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : @@ -4640,7 +4588,7 @@ namespace ts { propTypes.push(type); } const result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | commonFlags, name); - result.syntheticKind === SyntheticSymbolKind.UnionOrIntersection; + result.syntheticKind = SyntheticSymbolKind.UnionOrIntersection; result.containingType = containingType; result.hasNonUniformType = hasNonUniformType; result.isPartial = isPartial; @@ -5917,12 +5865,6 @@ namespace ts { function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - const hasSpread = (node.kind === SyntaxKind.TypeLiteral && - find((node as TypeLiteralNode).members, elt => elt.kind === SyntaxKind.SpreadTypeElement)); - if (hasSpread) { - return getTypeFromSpreadTypeLiteral(node, aliasSymbol, aliasTypeArguments); - } - // Deferred resolution of members is handled by resolveObjectTypeMembers if (isEmpty(node.symbol.members) && !aliasSymbol && !aliasTypeArguments) { links.resolvedType = emptyTypeLiteralType; @@ -5937,187 +5879,56 @@ namespace ts { return links.resolvedType; } - function getTypeFromSpreadTypeLiteral(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { - let spread: Type = emptyObjectType; - let members: Map; - let stringIndexInfo: IndexInfo; - let numberIndexInfo: IndexInfo; - for (const member of (node as TypeLiteralNode).members) { - if (member.kind === SyntaxKind.SpreadTypeElement) { - if (members) { - const type = createAnonymousType(node.symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); - spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); - members = undefined; - stringIndexInfo = undefined; - numberIndexInfo = undefined; - } - const type = getTypeFromTypeNode((member as SpreadTypeElement).type); - spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); - } - else if (member.kind !== SyntaxKind.IndexSignature && - member.kind !== SyntaxKind.CallSignature && - member.kind !== SyntaxKind.ConstructSignature) { - // it is an error for spread types to include index, call or construct signatures - const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0); - const text = getTextOfPropertyName(member.name); - const symbol = createSymbol(flags, text); - symbol.declarations = [member]; - symbol.valueDeclaration = member; - symbol.type = getTypeFromTypeNodeNoAlias((member as IndexSignatureDeclaration | PropertySignature | MethodSignature).type); - if (!members) { - members = createMap(); - } - members[symbol.name] = symbol; - } - } - if (members || stringIndexInfo || numberIndexInfo) { - const type = createAnonymousType(node.symbol, members || emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); - spread = getSpreadType(spread, type, node.symbol, aliasSymbol, aliasTypeArguments); - } - return spread; - } - /** * Since the source of spread types are object literals and type literals, which are not binary, * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { - const id = getTypeListId([left, right]); - if (id in spreadTypes) { - return spreadTypes[id]; - } + function getSpreadType(left: Type, right: Type, symbol: Symbol): ResolvedType { + Debug.assert(!!(left.flags & TypeFlags.Object) && !!(right.flags & TypeFlags.Object), "Only object types may be spread."); + const members = createMap(); + const skippedPrivateMembers = createMap(); + const stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); + const numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); - // any spreads to any - if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { - return anyType; - } - // flatten intersections to objects if all member types are objects - if (left.flags & TypeFlags.Intersection) { - left = resolveObjectIntersection(left as IntersectionType); - } - if (right.flags & TypeFlags.Intersection) { - right = resolveObjectIntersection(right as IntersectionType); - } - // distribute unions - if (left.flags & TypeFlags.Union) { - const spreads = map((left as UnionType).types, - t => getSpreadType(t, right, symbol, aliasSymbol, aliasTypeArguments)); - return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); - } - if (right.flags & TypeFlags.Union) { - const spreads = map((right as UnionType).types, - t => getSpreadType(left, t, symbol, aliasSymbol, aliasTypeArguments)); - return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); - } - // skip primitives - if (left.flags & TypeFlags.Primitive && right.flags & TypeFlags.Primitive) { - return emptyObjectType; + const isFromSpread = right.symbol !== symbol; + for (const rightProp of getPropertiesOfType(right)) { + if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { + skippedPrivateMembers[rightProp.name] = true; + } + else if (!(rightProp.flags & SymbolFlags.Method && isFromSpread) && + !(rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor))) { + // skip methods from spreads and accessors with setters but no getters + members[rightProp.name] = rightProp; + } } - else if (left.flags & TypeFlags.Primitive) { - return right; - } - else if (right.flags & TypeFlags.Primitive) { - return left; - } - - // spread simplifications - if (left.flags & TypeFlags.Spread && - right.flags & TypeFlags.TypeParameter && - (left as SpreadType).right.flags & TypeFlags.TypeParameter && - right.symbol === (left as SpreadType).right.symbol) { - // for types like T ... T, just return ... T - return left; - } - if (left.flags & TypeFlags.Spread && - right.flags & TypeFlags.Object && - (left as SpreadType).right.flags & TypeFlags.Object) { - // simplify two adjacent object types: T ... { x } ... { y } becomes T ... { x, y } - const simplified = getSpreadType(right, (left as SpreadType).right, symbol, aliasSymbol, aliasTypeArguments); - return getSpreadType((left as SpreadType).left, simplified, symbol, aliasSymbol, aliasTypeArguments); - } - if (right.flags & TypeFlags.Spread) { - // spread is right associative and associativity applies, so transform - // (T ... U) ... V to T ... (U ... V) - const rspread = right as SpreadType; - if (rspread.left === emptyObjectType) { - // ... U ... ({} ... T) => ... U ... T - return getSpreadType(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments); - } - return getSpreadType(getSpreadType(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments), - rspread.right, symbol, aliasSymbol, aliasTypeArguments); - } - - // create an object type if left and right are both objects, - // otherwise create a spread type - if (right.flags & TypeFlags.Object && left.flags & TypeFlags.Object) { - const members = createMap(); - const skippedPrivateMembers = createMap(); - const stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); - const numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); - - const isFromSpread = right.symbol !== symbol; - for (const rightProp of getPropertiesOfType(right)) { - if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { - skippedPrivateMembers[rightProp.name] = true; - } - else if (!(rightProp.flags & SymbolFlags.Method && isFromSpread) && - !(rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor))) { - // skip methods from spreads and accessors with setters but no getters - members[rightProp.name] = rightProp; - } - } - for (const leftProp of getPropertiesOfType(left)) { - if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor) - || leftProp.name in skippedPrivateMembers) { - continue; - } - if (leftProp.name in members) { - const rightProp = members[leftProp.name]; - if (rightProp.flags & SymbolFlags.Optional) { - const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations); - const flags = SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | (leftProp.flags & SymbolFlags.Optional); - const result = createSymbol(flags, leftProp.name); - result.syntheticKind = SyntheticSymbolKind.Spread; - result.leftSpread = leftProp; - result.rightSpread = rightProp; - result.declarations = declarations; - if (declarations.length) { - result.valueDeclaration = declarations[0]; - } - result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp); - members[leftProp.name] = result; + for (const leftProp of getPropertiesOfType(left)) { + if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor) + || leftProp.name in skippedPrivateMembers) { + continue; + } + if (leftProp.name in members) { + const rightProp = members[leftProp.name]; + if (rightProp.flags & SymbolFlags.Optional) { + const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations); + const flags = SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | (leftProp.flags & SymbolFlags.Optional); + const result = createSymbol(flags, leftProp.name); + result.syntheticKind = SyntheticSymbolKind.Spread; + result.leftSpread = leftProp; + result.rightSpread = rightProp; + result.declarations = declarations; + if (declarations.length) { + result.valueDeclaration = declarations[0]; } - } - else { - members[leftProp.name] = leftProp; + result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp); + members[leftProp.name] = result; } } - return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); - } - const spread = spreadTypes[id] = createType(TypeFlags.Spread) as SpreadType; - Debug.assert(!!(left.flags & (TypeFlags.Spread | TypeFlags.Object)), "Left flags: " + left.flags.toString(2)); - Debug.assert(!!(right.flags & (TypeFlags.TypeParameter | TypeFlags.Intersection | TypeFlags.Index | TypeFlags.IndexedAccess | TypeFlags.Object)), "Right flags: " + right.flags.toString(2)); - spread.symbol = symbol; - spread.left = left as SpreadType | ResolvedType; - spread.right = right as TypeParameter | IntersectionType | IndexType | IndexedAccessType | ResolvedType; - spread.aliasSymbol = aliasSymbol; - spread.aliasTypeArguments = aliasTypeArguments; - return spread; - } - - function resolveObjectIntersection(intersection: IntersectionType): IntersectionType | ResolvedType { - if (find(intersection.types, t => !(t.flags & TypeFlags.Object))) { - return intersection; - } - const properties = getPropertiesOfType(intersection); - const members = createMap(); - for (const property of properties) { - members[property.name] = property; + else { + members[leftProp.name] = leftProp; + } } - const stringIndex = getIndexInfoOfType(intersection, IndexKind.String); - const numberIndex = getIndexInfoOfType(intersection, IndexKind.Number); - return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndex, numberIndex); + return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } function createLiteralType(flags: TypeFlags, text: string) { @@ -6535,10 +6346,6 @@ namespace ts { if (type.flags & TypeFlags.Intersection) { return getIntersectionType(instantiateList((type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes); } - if (type.flags & TypeFlags.Spread) { - const spread = type as SpreadType; - return getSpreadType(instantiateType(spread.left, mapper), instantiateType(spread.right, mapper), type.symbol, type.aliasSymbol, mapper.targetTypes); - } if (type.flags & TypeFlags.Index) { return getIndexType(instantiateType((type).type, mapper)); } @@ -7089,30 +6896,7 @@ namespace ts { } } - if (source.flags & TypeFlags.Spread && target.flags & TypeFlags.Spread) { - // you only see this for spreads with type parameters - if (!(spreadTypeRelatedTo(source as SpreadType, target as SpreadType, /*atRightEdge*/ true))) { - if (reportErrors) { - reportRelationError(headMessage, source, target); - } - return Ternary.False; - } - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; - const apparentSource = getApparentType(source); - if (result = objectTypeRelatedTo(apparentSource, source, getApparentType(target), reportStructuralErrors)) { - errorInfo = saveErrorInfo; - return result; - } - } - if (source.flags & TypeFlags.TypeParameter) { - if (target.flags & TypeFlags.Spread) { - // T is assignable to ...T - if (source.symbol === (target as SpreadType).right.symbol - && (target as SpreadType).left === emptyObjectType) { - return Ternary.True; - } - } let constraint = getConstraintOfTypeParameter(source); if (!constraint || constraint.flags & TypeFlags.Any) { @@ -7164,32 +6948,6 @@ namespace ts { return Ternary.False; } - function spreadTypeRelatedTo(source: SpreadType, target: SpreadType, atRightEdge?: boolean): boolean { - // If the right side of a spread type is ObjectType, then the left side must be a Spread. - // Structural compatibility of the spreads' object types are checked separately in isRelatedTo, - // so just skip them for now. - if (source.right.flags & TypeFlags.Object || target.right.flags & TypeFlags.Object) { - return atRightEdge && - spreadTypeRelatedTo(source.right.flags & TypeFlags.Object ? source.left as SpreadType : source, - target.right.flags & TypeFlags.Object ? target.left as SpreadType : target); - } - // If both right sides are type parameters, intersections, index types or indexed access types, - // then they must be identical for the spread types to be related. - // It also means that the left sides are either spread types or object types. - - // if one left is object and the other is spread, that means the second has another type parameter. which isn't allowed - if (target.right !== source.right) { - return false; - } - if (source.left.flags & TypeFlags.Spread && target.left.flags & TypeFlags.Spread) { - // If the left sides are both spread types, then recursively check them. - return spreadTypeRelatedTo(source.left as SpreadType, target.left as SpreadType); - } - // If the left sides are both object types, then we should be at the end and both should be emptyObjectType. - // If not, we can't know what properties might have been overwritten, so fail. - return source.left === emptyObjectType && target.left === emptyObjectType; - } - function isIdenticalTo(source: Type, target: Type): Ternary { let result: Ternary; if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { @@ -11167,6 +10925,10 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadElementExpression).expression); + if (!(type.flags & TypeFlags.Object)) { + error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); + return unknownType; + } spread = getSpreadType(spread, type, node.symbol); continue; } @@ -15403,13 +15165,6 @@ namespace ts { checkTypeForDuplicateIndexSignatures(node); checkObjectTypeForDuplicateDeclarations(node); } - if (find(node.members, p => p.kind === SyntaxKind.SpreadTypeElement)) { - for (const signature of filter(node.members, p => p.kind === SyntaxKind.IndexSignature || - p.kind === SyntaxKind.CallSignature || - p.kind === SyntaxKind.ConstructSignature)) { - error(signature, Diagnostics.Type_literals_with_spreads_cannot_contain_index_call_or_construct_signatures); - } - } } } @@ -17467,9 +17222,7 @@ namespace ts { // perform property check if property or indexer is declared in 'type' // this allows to rule out cases when both property and indexer are inherited from the base class let errorNode: Node; - if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || - prop.parent === containingType.symbol || - containingType.flags & TypeFlags.Spread) { + if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { errorNode = prop.valueDeclaration; } else if (indexDeclaration) { @@ -20699,12 +20452,6 @@ namespace ts { checkGrammarHeritageClause(heritageClause); } } - - let result: TypeElement; - if (result = find(node.members, e => e.kind === SyntaxKind.SpreadTypeElement)) { - return grammarErrorOnNode(result, Diagnostics.Interface_declaration_cannot_contain_a_spread_property); - } - return false; } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 7a23ba8722bdd..0bba375a2cb2e 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1138,13 +1138,6 @@ namespace ts { writeLine(); } - function emitSpreadTypeElement(type: SpreadTypeElement) { - write("..."); - emitType(type.type); - write(";"); - writeLine(); - } - function emitVariableDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration) { // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted // so there is no check needed to see if declaration is visible @@ -1729,8 +1722,6 @@ namespace ts { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: return emitPropertyDeclaration(node); - case SyntaxKind.SpreadTypeElement: - return emitSpreadTypeElement(node as SpreadTypeElement); case SyntaxKind.EnumMember: return emitEnumMemberDeclaration(node); case SyntaxKind.ExportAssignment: diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1d45e96cb6f6b..58c59b18f5e45 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1983,14 +1983,10 @@ "category": "Error", "code": 2697 }, - "Interface declaration cannot contain a spread property.": { + "Spread types may only be created from object types.": { "category": "Error", "code": 2698 }, - "Type literals with spreads cannot contain index, call or construct signatures.": { - "category": "Error", - "code": 2699 - }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac41d78bb1232..464f6ca01d802 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -76,8 +76,6 @@ namespace ts { visitNode(cbNode, (node).objectAssignmentInitializer); case SyntaxKind.SpreadElementExpression: return visitNode(cbNode, (node).expression); - case SyntaxKind.SpreadTypeElement: - return visitNode(cbNode, (node as SpreadTypeElement).type); case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -2346,10 +2344,6 @@ namespace ts { if (token() === SyntaxKind.OpenBracketToken) { return true; } - // spread elements are type members - if (token() === SyntaxKind.DotDotDotToken) { - return true; - } // Try to get the first property-like token following all modifiers if (isLiteralPropertyName()) { idToken = token(); @@ -2375,9 +2369,6 @@ namespace ts { if (token() === SyntaxKind.NewKeyword && lookAhead(isStartOfConstructSignature)) { return parseSignatureMember(SyntaxKind.ConstructSignature); } - if (token() === SyntaxKind.DotDotDotToken) { - return parseSpreadTypeElement(); - } const fullStart = getNodePos(); const modifiers = parseModifiers(); if (isIndexSignature()) { @@ -2386,14 +2377,6 @@ namespace ts { return parsePropertyOrMethodSignature(fullStart, modifiers); } - function parseSpreadTypeElement() { - const element = createNode(SyntaxKind.SpreadTypeElement, scanner.getStartPos()) as SpreadTypeElement; - parseTokenNode(); // parse `...` - element.type = parseType(); - parseTypeMemberSemicolon(); - return finishNode(element); - } - function isStartOfConstructSignature() { nextToken(); return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ba5e6b2db9971..d3b4cb3b6e7df 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -321,8 +321,6 @@ namespace ts { PropertyAssignment, ShorthandPropertyAssignment, SpreadElementExpression, - SpreadTypeElement, - // Enum EnumMember, @@ -664,11 +662,6 @@ namespace ts { initializer?: Expression; // Optional initializer } - // @kind(SyntaxKind.SpreadTypeElement) - export interface SpreadTypeElement extends TypeElement { - type: TypeNode; - } - // @kind(SyntaxKind.PropertyDeclaration) export interface PropertyDeclaration extends ClassElement { kind: SyntaxKind.PropertyDeclaration; @@ -2521,7 +2514,7 @@ namespace ts { Merged = 0x02000000, // Merged symbol (created during program binding) Transient = 0x04000000, // Transient symbol (created during type check) Prototype = 0x08000000, // Prototype property (no source representation) - SyntheticProperty = 0x10000000, // Property in union, intersection or spread type + SyntheticProperty = 0x10000000, // Property in union or intersection type Optional = 0x20000000, // Optional property ExportStar = 0x40000000, // Export * declaration @@ -2711,7 +2704,6 @@ namespace ts { ContainsObjectLiteral = 1 << 22, // Type is or contains object literal type /* @internal */ ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type - Spread = 1 << 24, // Spread types /* @internal */ Nullable = Undefined | Null, @@ -2729,12 +2721,12 @@ namespace ts { BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, UnionOrIntersection = Union | Intersection, - StructuredType = Object | Union | Intersection | Spread, + StructuredType = Object | Union | Intersection, StructuredOrTypeParameter = StructuredType | TypeParameter, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | Spread, + Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol, NotUnionOrUnit = Any | ESSymbol | Object, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, @@ -2849,12 +2841,6 @@ namespace ts { export type StructuredType = ObjectType | UnionType | IntersectionType; - /* @internal */ - export interface SpreadType extends Type { - left: SpreadType | ResolvedType; - right: TypeParameter | IntersectionType | IndexType | IndexedAccessType | ResolvedType; - } - /* @internal */ // An instantiated anonymous type has a target and a mapper export interface AnonymousType extends ObjectType { @@ -2868,7 +2854,7 @@ namespace ts { } /* @internal */ - // Resolved object, spread, union, or intersection type + // Resolved object, union, or intersection type export interface ResolvedType extends ObjectType, UnionOrIntersectionType { members: SymbolTable; // Properties by name properties: Symbol[]; // Properties diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index cc61445effed1..28f2e12248bbe 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -278,7 +278,7 @@ interface ObjectConstructor { * @param target The target object to copy to. * @param source The source object from which to copy properties. */ - assign(target: T, source: U): { ...T, ...U }; + assign(target: T, source: U): T & U; /** * Copy the values of all of the enumerable own properties from one or more source objects to a @@ -287,7 +287,7 @@ interface ObjectConstructor { * @param source1 The first source object from which to copy properties. * @param source2 The second source object from which to copy properties. */ - assign(target: T, source1: U, source2: V): { ...T, ...U, ...V }; + assign(target: T, source1: U, source2: V): T & U & V; /** * Copy the values of all of the enumerable own properties from one or more source objects to a @@ -297,7 +297,7 @@ interface ObjectConstructor { * @param source2 The second source object from which to copy properties. * @param source3 The third source object from which to copy properties. */ - assign(target: T, source1: U, source2: V, source3: W): { ...T, ...U, ...V, ...W }; + assign(target: T, source1: U, source2: V, source3: W): T & U & V & W; /** * Copy the values of all of the enumerable own properties from one or more source objects to a From a6320203bec279d0d8db6ce9d479aba29ef0d388 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 2 Nov 2016 16:31:04 -0700 Subject: [PATCH 62/85] Fix lint --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c6924e2cb0aa8..872aad6b046b7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4526,7 +4526,7 @@ namespace ts { * type itself. Note that the apparent type of a union type is the union type itself. */ function getApparentType(type: Type): Type { - let t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(type) : type; + const t = type.flags & TypeFlags.TypeParameter ? getApparentTypeOfTypeParameter(type) : type; return t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : From a077fd104aa6be0237bc6dfe00f57528c6fb89e1 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Nov 2016 09:39:58 -0700 Subject: [PATCH 63/85] Remove spread type tests from spread tests --- tests/baselines/reference/objectSpread.js | 47 +--- .../baselines/reference/objectSpread.symbols | 225 +++++------------- tests/baselines/reference/objectSpread.types | 140 +---------- .../reference/objectSpreadGeneric.errors.txt | 148 ------------ .../reference/objectSpreadGeneric.js | 141 ----------- .../objectSpreadIndexSignature.errors.txt | 35 --- .../reference/objectSpreadIndexSignature.js | 56 ++--- .../objectSpreadIndexSignature.symbols | 42 ++++ .../objectSpreadIndexSignature.types | 52 ++++ .../reference/objectSpreadNegative.errors.txt | 135 +++++------ .../reference/objectSpreadNegative.js | 86 +++---- .../objectSpreadNegativeParse.errors.txt | 14 +- .../types/spread/interfaceSpread.ts | 8 - .../conformance/types/spread/objectSpread.ts | 23 +- .../types/spread/objectSpreadGeneric.ts | 72 ------ .../spread/objectSpreadIndexSignature.ts | 25 +- .../types/spread/objectSpreadInference.ts | 19 -- .../types/spread/objectSpreadIntersection.ts | 36 --- .../types/spread/objectSpreadNegative.ts | 47 ++-- .../types/spread/objectSpreadScenarios.ts | 17 -- .../types/spread/objectSpreadUnion.ts | 23 -- .../fourslash/findAllRefsForObjectSpread.ts | 4 +- .../fourslash/goToDefinitionObjectSpread.ts | 4 +- tests/cases/fourslash/renameObjectSpread.ts | 4 +- 24 files changed, 348 insertions(+), 1055 deletions(-) delete mode 100644 tests/baselines/reference/objectSpreadGeneric.errors.txt delete mode 100644 tests/baselines/reference/objectSpreadGeneric.js delete mode 100644 tests/baselines/reference/objectSpreadIndexSignature.errors.txt create mode 100644 tests/baselines/reference/objectSpreadIndexSignature.symbols create mode 100644 tests/baselines/reference/objectSpreadIndexSignature.types delete mode 100644 tests/cases/conformance/types/spread/interfaceSpread.ts delete mode 100644 tests/cases/conformance/types/spread/objectSpreadGeneric.ts delete mode 100644 tests/cases/conformance/types/spread/objectSpreadInference.ts delete mode 100644 tests/cases/conformance/types/spread/objectSpreadIntersection.ts delete mode 100644 tests/cases/conformance/types/spread/objectSpreadScenarios.ts delete mode 100644 tests/cases/conformance/types/spread/objectSpreadUnion.ts diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index 23729d4cd6f21..c19ead478cbd8 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -35,13 +35,8 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null, undefined, functions and primitives result in { } -let spreadNull = { ...null }; -let spreadUndefind = { ...undefined }; -let spreadNum = { ...12 }; -let spreadBool = { ...false }; +// functions result in { } let spreadFunc = { ...(function () { }) }; -let spreadStr = { ...'foo' }; // methods are not enumerable class C { p = 1; m() { } } @@ -80,22 +75,6 @@ let computedAfter: { a: number, b: string, "at the end": number } = let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } -// generics -function f(t: T, u: U): { ...T, ...U, id: string } { - return { ...t, ...u, id: 'id' }; -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) -let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) -let overlapConflict: { id:string, a: string } = - f({ a: 1 }, { a: 'mismatch' }) -let overwriteId: { id: string, a: number, c: number, d: string } = - f({ a: 1, id: true }, { c: 1, d: 'no' }) - -class D { m() { }; q = 2; } -let classesAreWrong: { id: string, ...C, ...D } = - f(new C(), new D()) //// [objectSpread.js] @@ -128,13 +107,8 @@ var propertyNested = __assign({ a: __assign({}, o) }); var op = { get a() { return 6; } }; var getter = __assign({}, op, { c: 7 }); getter.a = 12; -// null, undefined, functions and primitives result in { } -var spreadNull = __assign({}, null); -var spreadUndefind = __assign({}, undefined); -var spreadNum = __assign({}, 12); -var spreadBool = __assign({}, false); +// functions result in { } var spreadFunc = __assign({}, (function () { })); -var spreadStr = __assign({}, 'foo'); // methods are not enumerable var C = (function () { function C() { @@ -167,21 +141,4 @@ var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, // shortcut syntax var a = 12; var shortCutted = __assign({}, o, { a: a }); -// generics -function f(t, u) { - return __assign({}, t, u, { id: 'id' }); -} -var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false }); -var overlap = f({ a: 1 }, { a: 2, b: 'extra' }); -var overlapConflict = f({ a: 1 }, { a: 'mismatch' }); -var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' }); -var D = (function () { - function D() { - this.q = 2; - } - D.prototype.m = function () { }; - ; - return D; -}()); -var classesAreWrong = f(new C(), new D()); var _a, _b, _c; diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 039be9e0d7df5..b95f8273724c2 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -150,224 +150,127 @@ getter.a = 12; >getter : Symbol(getter, Decl(objectSpread.ts, 32, 3)) >a : Symbol(a, Decl(objectSpread.ts, 32, 13)) -// null, undefined, functions and primitives result in { } -let spreadNull = { ...null }; ->spreadNull : Symbol(spreadNull, Decl(objectSpread.ts, 37, 3)) - -let spreadUndefind = { ...undefined }; ->spreadUndefind : Symbol(spreadUndefind, Decl(objectSpread.ts, 38, 3)) - -let spreadNum = { ...12 }; ->spreadNum : Symbol(spreadNum, Decl(objectSpread.ts, 39, 3)) - -let spreadBool = { ...false }; ->spreadBool : Symbol(spreadBool, Decl(objectSpread.ts, 40, 3)) - +// functions result in { } let spreadFunc = { ...(function () { }) }; ->spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 41, 3)) - -let spreadStr = { ...'foo' }; ->spreadStr : Symbol(spreadStr, Decl(objectSpread.ts, 42, 3)) +>spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 42, 29)) ->p : Symbol(C.p, Decl(objectSpread.ts, 45, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 45, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 37, 42)) +>p : Symbol(C.p, Decl(objectSpread.ts, 40, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 40, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 46, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 29)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 29)) +>c : Symbol(c, Decl(objectSpread.ts, 41, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 37, 42)) +>C : Symbol(C, Decl(objectSpread.ts, 37, 42)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 47, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 47, 14)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 42, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 42, 14)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 50, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) ->plus : Symbol(plus, Decl(objectSpread.ts, 50, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 45, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 45, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 45, 23)) +>plus : Symbol(plus, Decl(objectSpread.ts, 45, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 50, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 50, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 45, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 45, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 45, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 54, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 54, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 54, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 49, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 49, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 49, 33)) { ...o, a: 'wrong type?' } ->a : Symbol(a, Decl(objectSpread.ts, 55, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 50, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 56, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 56, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 56, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 51, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 51, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 51, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 57, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 52, 5)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 58, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 58, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 58, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 53, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 53, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 53, 32)) { ...o, ...swap }; // optional let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 62, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 62, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 57, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 57, 22)) let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 63, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 58, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 58, 21)) let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 64, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 59, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 59, 21)) let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 65, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 65, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 60, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 60, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 66, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 66, 25)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 61, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 61, 25)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 67, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 67, 30)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 62, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 62, 30)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 68, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 68, 18)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 63, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 63, 18)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 71, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 71, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 71, 31)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 66, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 66, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 66, 31)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 72, 5)) ->b : Symbol(b, Decl(objectSpread.ts, 72, 38)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 67, 5)) +>b : Symbol(b, Decl(objectSpread.ts, 67, 38)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 73, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 73, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 73, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 73, 43)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 68, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 68, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 68, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 68, 43)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 74, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 74, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 69, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 69, 34)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 75, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 75, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 75, 31)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 70, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 70, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 70, 31)) { ...o, b: 'yeah', ['at the end']: 14 } ->b : Symbol(b, Decl(objectSpread.ts, 76, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 76, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 71, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 71, 22)) // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 78, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 73, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 79, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 79, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 79, 29)) ->a : Symbol(a, Decl(objectSpread.ts, 79, 51)) - -// generics -function f(t: T, u: U): { ...T, ...U, id: string } { ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->T : Symbol(T, Decl(objectSpread.ts, 82, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 82, 13)) ->t : Symbol(t, Decl(objectSpread.ts, 82, 17)) ->T : Symbol(T, Decl(objectSpread.ts, 82, 11)) ->u : Symbol(u, Decl(objectSpread.ts, 82, 22)) ->U : Symbol(U, Decl(objectSpread.ts, 82, 13)) ->T : Symbol(T, Decl(objectSpread.ts, 82, 11)) ->U : Symbol(U, Decl(objectSpread.ts, 82, 13)) ->id : Symbol(id, Decl(objectSpread.ts, 82, 43)) - - return { ...t, ...u, id: 'id' }; ->id : Symbol(id, Decl(objectSpread.ts, 83, 24)) -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : Symbol(exclusive, Decl(objectSpread.ts, 85, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 85, 16)) ->a : Symbol(a, Decl(objectSpread.ts, 85, 28)) ->b : Symbol(b, Decl(objectSpread.ts, 85, 39)) ->c : Symbol(c, Decl(objectSpread.ts, 85, 50)) ->d : Symbol(d, Decl(objectSpread.ts, 85, 61)) - - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 86, 7)) ->b : Symbol(b, Decl(objectSpread.ts, 86, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 86, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 86, 36)) - -let overlap: { id: string, a: number, b: string } = ->overlap : Symbol(overlap, Decl(objectSpread.ts, 87, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 87, 14)) ->a : Symbol(a, Decl(objectSpread.ts, 87, 26)) ->b : Symbol(b, Decl(objectSpread.ts, 87, 37)) - - f({ a: 1 }, { a: 2, b: 'extra' }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 88, 17)) ->b : Symbol(b, Decl(objectSpread.ts, 88, 23)) - -let overlapConflict: { id:string, a: string } = ->overlapConflict : Symbol(overlapConflict, Decl(objectSpread.ts, 89, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 89, 22)) ->a : Symbol(a, Decl(objectSpread.ts, 89, 33)) - - f({ a: 1 }, { a: 'mismatch' }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 7)) ->a : Symbol(a, Decl(objectSpread.ts, 90, 17)) - -let overwriteId: { id: string, a: number, c: number, d: string } = ->overwriteId : Symbol(overwriteId, Decl(objectSpread.ts, 91, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 91, 18)) ->a : Symbol(a, Decl(objectSpread.ts, 91, 30)) ->c : Symbol(c, Decl(objectSpread.ts, 91, 41)) ->d : Symbol(d, Decl(objectSpread.ts, 91, 52)) - - f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->a : Symbol(a, Decl(objectSpread.ts, 92, 7)) ->id : Symbol(id, Decl(objectSpread.ts, 92, 13)) ->c : Symbol(c, Decl(objectSpread.ts, 92, 27)) ->d : Symbol(d, Decl(objectSpread.ts, 92, 33)) - -class D { m() { }; q = 2; } ->D : Symbol(D, Decl(objectSpread.ts, 92, 44)) ->m : Symbol(D.m, Decl(objectSpread.ts, 94, 9)) ->q : Symbol(D.q, Decl(objectSpread.ts, 94, 18)) - -let classesAreWrong: { id: string, ...C, ...D } = ->classesAreWrong : Symbol(classesAreWrong, Decl(objectSpread.ts, 95, 3)) ->id : Symbol(id, Decl(objectSpread.ts, 95, 22)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 29)) ->D : Symbol(D, Decl(objectSpread.ts, 92, 44)) - - f(new C(), new D()) ->f : Symbol(f, Decl(objectSpread.ts, 79, 55)) ->C : Symbol(C, Decl(objectSpread.ts, 42, 29)) ->D : Symbol(D, Decl(objectSpread.ts, 92, 44)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 74, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 74, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 74, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 74, 51)) + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 78f4f7583d939..e9b9a6421c297 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -223,36 +223,13 @@ getter.a = 12; >a : number >12 : 12 -// null, undefined, functions and primitives result in { } -let spreadNull = { ...null }; ->spreadNull : {} ->{ ...null } : {} ->null : null - -let spreadUndefind = { ...undefined }; ->spreadUndefind : {} ->{ ...undefined } : {} ->undefined : any - -let spreadNum = { ...12 }; ->spreadNum : {} ->{ ...12 } : {} - -let spreadBool = { ...false }; ->spreadBool : {} ->{ ...false } : {} ->false : false - +// functions result in { } let spreadFunc = { ...(function () { }) }; >spreadFunc : {} >{ ...(function () { }) } : {} >(function () { }) : () => void >function () { } : () => void -let spreadStr = { ...'foo' }; ->spreadStr : {} ->{ ...'foo' } : {} - // methods are not enumerable class C { p = 1; m() { } } >C : C @@ -421,119 +398,4 @@ let shortCutted: { a: number, b: string } = { ...o, a } >o : any >a : number -// generics -function f(t: T, u: U): { ...T, ...U, id: string } { ->f : (t: T, u: U) => { ...T; ...U; id: string; } ->T : T ->U : U ->t : T ->T : T ->u : U ->U : U ->T : T ->U : U ->id : string - - return { ...t, ...u, id: 'id' }; ->{ ...t, ...u, id: 'id' } : { ...T; ...U; id: string; } ->t : any ->u : any ->id : string ->'id' : "id" -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = ->exclusive : { id: string; a: number; b: string; c: string; d: boolean; } ->id : string ->a : number ->b : string ->c : string ->d : boolean - - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) ->f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { id: string; c: string; d: boolean; a: number; b: string; } ->f : (t: T, u: U) => { ...T; ...U; id: string; } ->{ a: 1, b: 'yes' } : { a: number; b: string; } ->a : number ->1 : 1 ->b : string ->'yes' : "yes" ->{ c: 'no', d: false } : { c: string; d: false; } ->c : string ->'no' : "no" ->d : boolean ->false : false - -let overlap: { id: string, a: number, b: string } = ->overlap : { id: string; a: number; b: string; } ->id : string ->a : number ->b : string - - f({ a: 1 }, { a: 2, b: 'extra' }) ->f({ a: 1 }, { a: 2, b: 'extra' }) : { id: string; a: number; b: string; } ->f : (t: T, u: U) => { ...T; ...U; id: string; } ->{ a: 1 } : { a: number; } ->a : number ->1 : 1 ->{ a: 2, b: 'extra' } : { a: number; b: string; } ->a : number ->2 : 2 ->b : string ->'extra' : "extra" - -let overlapConflict: { id:string, a: string } = ->overlapConflict : { id: string; a: string; } ->id : string ->a : string - - f({ a: 1 }, { a: 'mismatch' }) ->f({ a: 1 }, { a: 'mismatch' }) : { id: string; a: string; } ->f : (t: T, u: U) => { ...T; ...U; id: string; } ->{ a: 1 } : { a: number; } ->a : number ->1 : 1 ->{ a: 'mismatch' } : { a: string; } ->a : string ->'mismatch' : "mismatch" - -let overwriteId: { id: string, a: number, c: number, d: string } = ->overwriteId : { id: string; a: number; c: number; d: string; } ->id : string ->a : number ->c : number ->d : string - - f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f({ a: 1, id: true }, { c: 1, d: 'no' }) : { id: string; c: number; d: string; a: number; } ->f : (t: T, u: U) => { ...T; ...U; id: string; } ->{ a: 1, id: true } : { a: number; id: true; } ->a : number ->1 : 1 ->id : boolean ->true : true ->{ c: 1, d: 'no' } : { c: number; d: string; } ->c : number ->1 : 1 ->d : string ->'no' : "no" - -class D { m() { }; q = 2; } ->D : D ->m : () => void ->q : number ->2 : 2 - -let classesAreWrong: { id: string, ...C, ...D } = ->classesAreWrong : { q: number; p: number; id: string; } ->id : string ->C : C ->D : D - - f(new C(), new D()) ->f(new C(), new D()) : { id: string; q: number; p: number; } ->f : (t: T, u: U) => { ...T; ...U; id: string; } ->new C() : C ->C : typeof C ->new D() : D ->D : typeof D diff --git a/tests/baselines/reference/objectSpreadGeneric.errors.txt b/tests/baselines/reference/objectSpreadGeneric.errors.txt deleted file mode 100644 index f1e2b7e4828f5..0000000000000 --- a/tests/baselines/reference/objectSpreadGeneric.errors.txt +++ /dev/null @@ -1,148 +0,0 @@ -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(9,5): error TS2322: Type '{ ...U }' is not assignable to type 'U'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(10,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(11,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...T; ...V }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(12,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(13,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(14,11): error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(16,11): error TS2322: Type '{ first: string; ...T; ...U }' is not assignable to type '{ first: string; ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(19,11): error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(26,11): error TS2322: Type '{ sn?: boolean; ...T; sn?: string | number; }' is not assignable to type '{ ...T; sn?: string | number | boolean; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(32,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(34,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(36,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(38,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; second: string; secondsecond: string; third: string; ...T; ...U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(42,11): error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(44,11): error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(46,11): error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(57,5): error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...keyof T }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(58,5): error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...keyof U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(61,5): error TS2322: Type '{ ...K }' is not assignable to type '{ ...keyof T }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(62,5): error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...K }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(63,5): error TS2322: Type '{ ...J }' is not assignable to type '{ ...keyof U }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(64,5): error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...J }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(70,5): error TS2322: Type '{ ...U[J] }' is not assignable to type '{ ...T[K] }'. -tests/cases/conformance/types/spread/objectSpreadGeneric.ts(71,5): error TS2322: Type '{ ...T[K] }' is not assignable to type '{ ...U[J] }'. - - -==== tests/cases/conformance/types/spread/objectSpreadGeneric.ts (24 errors) ==== - function f(t: T, u: U, v: V): void { - let o: { ...T, ...U, ...V }; - let uus: { ...U, ...U}; - let us: { ...U }; - const same: { ...T, ...U, ...V } = o; // ok - uus = us; // ok, multiple spreads are equivalent to a single one - us = uus; // ok, multiple spreads are equivalent to a single one - us = u; // ok, type has at least all the properties of the spread - u = us; // error, might be missing a ton of stuff - ~ -!!! error TS2322: Type '{ ...U }' is not assignable to type 'U'. - const reversed: { ...V, ...U, ...T } = o; // error, reversed - ~~~~~~~~ -!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...V; ...U; ...T }'. - const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed - ~~~~~~~~~ -!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...T; ...V }'. - const missingT: { ...U, ...V } = o; // error, missing T - ~~~~~~~~ -!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...U; ...V }'. - const missingU: { ...T, ...V } = o; // error, missing U - ~~~~~~~~ -!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...V }'. - const missingV: { ...T, ...U } = o; // error, missing V - ~~~~~~~~ -!!! error TS2322: Type '{ ...T; ...U; ...V }' is not assignable to type '{ ...T; ...U }'. - const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok - const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // error, not assignable - ~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; ...U }' is not assignable to type '{ first: string; ...T; ...U }'. - - const emptyTarget: { } = { ...t, ...u } // ok - const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) - ~~~~~~~~~~~ -!!! error TS2322: Type '{}' is not assignable to type '{ ...T; ...U }'. - - // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to - // T ... { sn?: number | string | boolean } - let optionalNumber: { sn?: number }; - let optionalString: { sn?: string }; - let optionalBoolean: { sn?: boolean }; - const unionCutoff: { ...T, sn?: number | string | boolean } = - ~~~~~~~~~~~ -!!! error TS2322: Type '{ sn?: boolean; ...T; sn?: string | number; }' is not assignable to type '{ ...T; sn?: string | number | boolean; }'. - { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } - unionCutoff.sn; // ok - const optionalCutoff = { ...t, ...optionalNumber }; // ok - optionalCutoff.sn; // ok - - const interspersed: { first: string, ...T, second: string, ...U, third: string } = - ~~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable - const interspersedMissingU: { first: string, second: string, ...T, third: string } = - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; second: string; ...T; third: string; }'. - { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing - const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = - ~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }'. - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable - const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = - ~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; third: string; secondsecond: string; }' is not assignable to type '{ first: string; second: string; secondsecond: string; third: string; ...T; ...U }'. - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable - - - const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = - ~~~~~~~~~~~~~ -!!! error TS2322: Type '{ firrrrrrst: string; ...T; second: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable - const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = - ~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; ssssssssecond: string; ...U; third: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable - const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = - ~~~~~~~~~~~~ -!!! error TS2322: Type '{ first: string; ...T; second: string; ...U; thirrrrrrrd: string; }' is not assignable to type '{ first: string; ...T; second: string; ...U; third: string; }'. - { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable - } - - function indexAccessedTest(t: T, u: U, key1: K, key2: J) { - let k1: { ...keyof T }; - let k2: { ...keyof U }; - let k3: { ...K }; - let k4: { ...J }; - k1 = k1; // ok - k2 = k2; // ok - k1 = k2; // error - ~~ -!!! error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...keyof T }'. - k2 = k1; // error - ~~ -!!! error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...keyof U }'. - k3 = k3; // ok - k4 = k4; // ok - k1 = k3; // error - ~~ -!!! error TS2322: Type '{ ...K }' is not assignable to type '{ ...keyof T }'. - k3 = k1; // error - ~~ -!!! error TS2322: Type '{ ...keyof T }' is not assignable to type '{ ...K }'. - k2 = k4; // error - ~~ -!!! error TS2322: Type '{ ...J }' is not assignable to type '{ ...keyof U }'. - k4 = k2; // error - ~~ -!!! error TS2322: Type '{ ...keyof U }' is not assignable to type '{ ...J }'. - - let i1: { ...T[K] }; - let i2: { ...U[J] }; - i1 = i1; // ok - i2 = i2; // ok - i1 = i2; // error - ~~ -!!! error TS2322: Type '{ ...U[J] }' is not assignable to type '{ ...T[K] }'. - i2 = i1; // error - ~~ -!!! error TS2322: Type '{ ...T[K] }' is not assignable to type '{ ...U[J] }'. - } - \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadGeneric.js b/tests/baselines/reference/objectSpreadGeneric.js deleted file mode 100644 index 8e89ebeef6416..0000000000000 --- a/tests/baselines/reference/objectSpreadGeneric.js +++ /dev/null @@ -1,141 +0,0 @@ -//// [objectSpreadGeneric.ts] -function f(t: T, u: U, v: V): void { - let o: { ...T, ...U, ...V }; - let uus: { ...U, ...U}; - let us: { ...U }; - const same: { ...T, ...U, ...V } = o; // ok - uus = us; // ok, multiple spreads are equivalent to a single one - us = uus; // ok, multiple spreads are equivalent to a single one - us = u; // ok, type has at least all the properties of the spread - u = us; // error, might be missing a ton of stuff - const reversed: { ...V, ...U, ...T } = o; // error, reversed - const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed - const missingT: { ...U, ...V } = o; // error, missing T - const missingU: { ...T, ...V } = o; // error, missing U - const missingV: { ...T, ...U } = o; // error, missing V - const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok - const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // error, not assignable - - const emptyTarget: { } = { ...t, ...u } // ok - const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) - - // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to - // T ... { sn?: number | string | boolean } - let optionalNumber: { sn?: number }; - let optionalString: { sn?: string }; - let optionalBoolean: { sn?: boolean }; - const unionCutoff: { ...T, sn?: number | string | boolean } = - { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } - unionCutoff.sn; // ok - const optionalCutoff = { ...t, ...optionalNumber }; // ok - optionalCutoff.sn; // ok - - const interspersed: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable - const interspersedMissingU: { first: string, second: string, ...T, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing - const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable - const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable - - - const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = - { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable - const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable - const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable -} - -function indexAccessedTest(t: T, u: U, key1: K, key2: J) { - let k1: { ...keyof T }; - let k2: { ...keyof U }; - let k3: { ...K }; - let k4: { ...J }; - k1 = k1; // ok - k2 = k2; // ok - k1 = k2; // error - k2 = k1; // error - k3 = k3; // ok - k4 = k4; // ok - k1 = k3; // error - k3 = k1; // error - k2 = k4; // error - k4 = k2; // error - - let i1: { ...T[K] }; - let i2: { ...U[J] }; - i1 = i1; // ok - i2 = i2; // ok - i1 = i2; // error - i2 = i1; // error -} - - -//// [objectSpreadGeneric.js] -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; -}; -function f(t, u, v) { - var o; - var uus; - var us; - var same = o; // ok - uus = us; // ok, multiple spreads are equivalent to a single one - us = uus; // ok, multiple spreads are equivalent to a single one - us = u; // ok, type has at least all the properties of the spread - u = us; // error, might be missing a ton of stuff - var reversed = o; // error, reversed - var reversed2 = o; // error, U and T are still reversed - var missingT = o; // error, missing T - var missingU = o; // error, missing U - var missingV = o; // error, missing V - var atEnd = __assign({}, t, u, { second: 'foo' }); // ok - var atBeginning = __assign({ first: 'foo' }, t, u); // error, not assignable - var emptyTarget = __assign({}, t, u); // ok - var emptySource = {}; // error, {} is not assignable to U (or T) - // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to - // T ... { sn?: number | string | boolean } - var optionalNumber; - var optionalString; - var optionalBoolean; - var unionCutoff = __assign({}, optionalBoolean, t, optionalString, optionalNumber); - unionCutoff.sn; // ok - var optionalCutoff = __assign({}, t, optionalNumber); // ok - optionalCutoff.sn; // ok - var interspersed = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, not assignable - var interspersedMissingU = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3' }); // error, 'U' is missing - var interspersedOrder1 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // error, not assignable - var interspersedOrder2 = __assign({ first: '1' }, t, { second: '2' }, u, { third: '3', secondsecond: 'false' }); // error, not assignable - var mismatchFirst = __assign({ firrrrrrst: '1' }, t, { second: '2' }, u, { third: '3' }); // error, not assignable - var mismatchSecond = __assign({ first: '1' }, t, { ssssssssecond: '2' }, u, { third: '3' }); // error, not assignable - var mismatchLast = __assign({ first: '1' }, t, { second: '2' }, u, { thirrrrrrrd: '3' }); // error, not assignable -} -function indexAccessedTest(t, u, key1, key2) { - var k1; - var k2; - var k3; - var k4; - k1 = k1; // ok - k2 = k2; // ok - k1 = k2; // error - k2 = k1; // error - k3 = k3; // ok - k4 = k4; // ok - k1 = k3; // error - k3 = k1; // error - k2 = k4; // error - k4 = k2; // error - var i1; - var i2; - i1 = i1; // ok - i2 = i2; // ok - i1 = i2; // error - i2 = i1; // error -} diff --git a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt deleted file mode 100644 index d3faa2e6ff8f8..0000000000000 --- a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt +++ /dev/null @@ -1,35 +0,0 @@ -tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,39): error TS2699: Type literals with spreads cannot contain index, call or construct signatures. -tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(24,20): error TS2699: Type literals with spreads cannot contain index, call or construct signatures. - - -==== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts (2 errors) ==== - class C { - a: number; - c: boolean; - } - // index signatures are not allowed in object literals with spread types - let c: { ...C, b: string, c?: string, [n: number]: string }; - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2699: Type literals with spreads cannot contain index, call or construct signatures. - let n: number = c.a; - let s: string = c[12]; - interface Indexed { - [n: string]: number; - a: number; - } - let i: { ...Indexed, b: number }; - n = i[101]; - n = i.b; - interface Indexed2 { - [n: string]: boolean; - c: boolean; - } - let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; - let nb: number | boolean = ii[1001]; - - function f(t: T) { - let i: { ...T, [n: number]: string }; - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2699: Type literals with spreads cannot contain index, call or construct signatures. - } - \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js index ab18c0f24a942..22e92e6a844bf 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.js +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -1,46 +1,36 @@ //// [objectSpreadIndexSignature.ts] -class C { - a: number; - c: boolean; -} -// index signatures are not allowed in object literals with spread types -let c: { ...C, b: string, c?: string, [n: number]: string }; -let n: number = c.a; -let s: string = c[12]; interface Indexed { [n: string]: number; a: number; } -let i: { ...Indexed, b: number }; -n = i[101]; -n = i.b; interface Indexed2 { [n: string]: boolean; c: boolean; } -let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; -let nb: number | boolean = ii[1001]; - -function f(t: T) { - let i: { ...T, [n: number]: string }; -} +let indexed: Indexed; +let indexed2: Indexed2; +let i = { ...indexed, b: 11 }; +// only indexed has indexer, so i[101]: any +i[101]; +let ii = { ...indexed, ...indexed2 }; +// both have indexer, so i[1001]: number | boolean +ii[1001]; //// [objectSpreadIndexSignature.js] -var C = (function () { - function C() { +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; } - return C; -}()); -// index signatures are not allowed in object literals with spread types -var c; -var n = c.a; -var s = c[12]; -var i; -n = i[101]; -n = i.b; -var ii; -var nb = ii[1001]; -function f(t) { - var i; -} + return t; +}; +var indexed; +var indexed2; +var i = __assign({}, indexed, { b: 11 }); +// only indexed has indexer, so i[101]: any +i[101]; +var ii = __assign({}, indexed, indexed2); +// both have indexer, so i[1001]: number | boolean +ii[1001]; diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols new file mode 100644 index 0000000000000..c51e7f4532f98 --- /dev/null +++ b/tests/baselines/reference/objectSpreadIndexSignature.symbols @@ -0,0 +1,42 @@ +=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === +interface Indexed { +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0)) + + [n: string]: number; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 1, 5)) + + a: number; +>a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 1, 24)) +} +interface Indexed2 { +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1)) + + [n: string]: boolean; +>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 5)) + + c: boolean; +>c : Symbol(Indexed2.c, Decl(objectSpreadIndexSignature.ts, 5, 25)) +} +let indexed: Indexed; +>indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3)) +>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0)) + +let indexed2: Indexed2; +>indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 9, 3)) +>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1)) + +let i = { ...indexed, b: 11 }; +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3)) +>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 10, 21)) + +// only indexed has indexer, so i[101]: any +i[101]; +>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3)) + +let ii = { ...indexed, ...indexed2 }; +>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3)) + +// both have indexer, so i[1001]: number | boolean +ii[1001]; +>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3)) + diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types new file mode 100644 index 0000000000000..79a515e73742d --- /dev/null +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -0,0 +1,52 @@ +=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts === +interface Indexed { +>Indexed : Indexed + + [n: string]: number; +>n : string + + a: number; +>a : number +} +interface Indexed2 { +>Indexed2 : Indexed2 + + [n: string]: boolean; +>n : string + + c: boolean; +>c : boolean +} +let indexed: Indexed; +>indexed : Indexed +>Indexed : Indexed + +let indexed2: Indexed2; +>indexed2 : Indexed2 +>Indexed2 : Indexed2 + +let i = { ...indexed, b: 11 }; +>i : { b: number; a: number; } +>{ ...indexed, b: 11 } : { b: number; a: number; } +>indexed : any +>b : number +>11 : 11 + +// only indexed has indexer, so i[101]: any +i[101]; +>i[101] : any +>i : { b: number; a: number; } +>101 : 101 + +let ii = { ...indexed, ...indexed2 }; +>ii : { [x: string]: number | boolean; c: boolean; a: number; } +>{ ...indexed, ...indexed2 } : { [x: string]: number | boolean; c: boolean; a: number; } +>indexed : any +>indexed2 : any + +// both have indexer, so i[1001]: number | boolean +ii[1001]; +>ii[1001] : number | boolean +>ii : { [x: string]: number | boolean; c: boolean; a: number; } +>1001 : 1001 + diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index 1af94007dc15e..dc6a356708f12 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -1,30 +1,26 @@ -tests/cases/conformance/types/spread/objectSpreadNegative.ts(11,21): error TS2339: Property 'x' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(14,5): error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(13,21): error TS2339: Property 'x' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(16,5): error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'. Property 'sn' is optional in type '{ sn?: string | number; }' but required in type '{ sn: string | number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(20,5): error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(23,1): error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. Property 'b' is missing in type '{ s: string; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(22,1): error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. - Property 's' is missing in type 'Bool'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,36): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(30,12): error TS2339: Property 'null' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,17): error TS2339: Property 'undefined' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(36,11): error TS2339: Property 'toFixed' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(38,11): error TS2339: Property 'toFixed' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(40,11): error TS2339: Property 'length' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,11): error TS2339: Property 'charAt' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(45,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(49,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(55,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,48): error TS2699: Type literals with spreads cannot contain index, call or construct signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(57,69): error TS2699: Type literals with spreads cannot contain index, call or construct signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(64,9): error TS2322: Type '{ ...T & V }' is not assignable to type '{ ...T & U }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS2322: Type '{ ...U }' is not assignable to type 'U'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. + Property 's' is missing in type '{ b: boolean; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,24): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (21 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -34,7 +30,9 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS232 class PublicX { public x: number; } - let o2: { ...PublicX, ...PrivateOptionalX }; + let publicX: PublicX; + let privateOptionalX: PrivateOptionalX; + let o2 = { ...publicX, ...privateOptionalX }; let sn: number = o2.x; // error, x is private ~ !!! error TS2339: Property 'x' does not exist on type '{}'. @@ -49,15 +47,16 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS232 // assignability as target interface Bool { b: boolean }; interface Str { s: string }; - let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' - ~~~~~~ + let spread = { ...{ b: true }, ...{s: "foo" } }; + spread = { s: "foo" }; // error, missing 'b' + ~~~~~~ !!! error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'. !!! error TS2322: Property 'b' is missing in type '{ s: string; }'. - let b: Bool; + let b = { b: false }; spread = b; // error, missing 's' ~~~~~~ -!!! error TS2322: Type 'Bool' is not assignable to type '{ s: string; b: boolean; }'. -!!! error TS2322: Property 's' is missing in type 'Bool'. +!!! error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'. +!!! error TS2322: Property 's' is missing in type '{ b: boolean; }'. // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } @@ -67,34 +66,30 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS232 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } - // null and undefined are just skipped - let spreadNull = { ...null } - spreadNull.null; - ~~~~ -!!! error TS2339: Property 'null' does not exist on type '{}'. - let spreadUndefined = { ...undefined } - spreadUndefined.undefined; - ~~~~~~~~~ -!!! error TS2339: Property 'undefined' does not exist on type '{}'. - - // primitives and functions are skipped + // null, undefined and primitives are not allowed + let spreadNull = { ...null }; + ~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + let spreadUndefind = { ...undefined }; + ~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. let spreadNum = { ...12 }; - spreadNum.toFixed(); // error, no methods from number - ~~~~~~~ -!!! error TS2339: Property 'toFixed' does not exist on type '{}'. + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. let spreadSum = { ...1 + 1 }; + ~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. spreadSum.toFixed(); // error, no methods from number - ~~~~~~~ -!!! error TS2339: Property 'toFixed' does not exist on type '{}'. + let spreadBool = { ...false }; + ~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + spreadBool.valueOf(); // error, what were you thinking? let spreadStr = { ...'foo' }; + ~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. spreadStr.length; // error, no 'length' - ~~~~~~ -!!! error TS2339: Property 'length' does not exist on type '{}'. spreadStr.charAt(1); // error, no methods either - ~~~~~~ -!!! error TS2339: Property 'charAt' does not exist on type '{}'. - let spreadBool = { ...true }; - spreadBool.valueOf(); // error, what were you thinking? + // functions are skipped let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature ~~~~~~~~~~~~ @@ -114,27 +109,23 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(66,12): error TS232 ~ !!! error TS2339: Property 'm' does not exist on type '{ p: number; }'. - let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2699: Type literals with spreads cannot contain index, call or construct signatures. - ~~~~~~~~~~~~~~~ -!!! error TS2699: Type literals with spreads cannot contain index, call or construct signatures. - callableConstructableSpread(12); // error, no call signature - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ x: number; }' has no compatible call signatures. - new callableConstructableSpread(12); // error, no construct signature - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. - - function override(initial: U, override: U, t: T, v: V): U { - // { ... T & V } is not assignable to { ... T & U } - let tvs: { ...T & V }; - let mistake: { ...T & U } = tvs; - ~~~~~~~ -!!! error TS2322: Type '{ ...T & V }' is not assignable to type '{ ...T & U }'. - // { ...U } is not assignable to U + // generics + function f(t: T, u: U) { + return { ...t, ...u, id: 'id' }; + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + } + function override(initial: U, override: U): U { return { ...initial, ...override }; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ ...U }' is not assignable to type 'U'. + ~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. } + let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) + let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) + let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) + let overwriteId: { id: string, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 7187b6009bd39..4faacd9744450 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -8,7 +8,9 @@ class PrivateOptionalX { class PublicX { public x: number; } -let o2: { ...PublicX, ...PrivateOptionalX }; +let publicX: PublicX; +let privateOptionalX: PrivateOptionalX; +let o2 = { ...publicX, ...privateOptionalX }; let sn: number = o2.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; @@ -18,30 +20,27 @@ let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumbe // assignability as target interface Bool { b: boolean }; interface Str { s: string }; -let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' -let b: Bool; +let spread = { ...{ b: true }, ...{s: "foo" } }; +spread = { s: "foo" }; // error, missing 'b' +let b = { b: false }; spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// null and undefined are just skipped -let spreadNull = { ...null } -spreadNull.null; -let spreadUndefined = { ...undefined } -spreadUndefined.undefined; - -// primitives and functions are skipped +// null, undefined and primitives are not allowed +let spreadNull = { ...null }; +let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; -spreadNum.toFixed(); // error, no methods from number let spreadSum = { ...1 + 1 }; spreadSum.toFixed(); // error, no methods from number +let spreadBool = { ...false }; +spreadBool.valueOf(); // error, what were you thinking? let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either -let spreadBool = { ...true }; -spreadBool.valueOf(); // error, what were you thinking? +// functions are skipped let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature @@ -55,17 +54,21 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' -let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; -callableConstructableSpread(12); // error, no call signature -new callableConstructableSpread(12); // error, no construct signature - -function override(initial: U, override: U, t: T, v: V): U { - // { ... T & V } is not assignable to { ... T & U } - let tvs: { ...T & V }; - let mistake: { ...T & U } = tvs; - // { ...U } is not assignable to U +// generics +function f(t: T, u: U) { + return { ...t, ...u, id: 'id' }; +} +function override(initial: U, override: U): U { return { ...initial, ...override }; } +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) +let overwriteId: { id: string, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) //// [objectSpreadNegative.js] @@ -89,34 +92,34 @@ var PublicX = (function () { } return PublicX; }()); -var o2; +var publicX; +var privateOptionalX; +var o2 = __assign({}, publicX, privateOptionalX); var sn = o2.x; // error, x is private var optionalString; var optionalNumber; var allOptional = __assign({}, optionalString, optionalNumber); ; ; -var spread = { s: 'foo' }; // error, missing 'b' -var b; +var spread = __assign({ b: true }, { s: "foo" }); +spread = { s: "foo" }; // error, missing 'b' +var b = { b: false }; spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); -// null and undefined are just skipped +// null, undefined and primitives are not allowed var spreadNull = __assign({}, null); -spreadNull.null; -var spreadUndefined = __assign({}, undefined); -spreadUndefined.undefined; -// primitives and functions are skipped +var spreadUndefind = __assign({}, undefined); var spreadNum = __assign({}, 12); -spreadNum.toFixed(); // error, no methods from number var spreadSum = __assign({}, 1 + 1); spreadSum.toFixed(); // error, no methods from number +var spreadBool = __assign({}, false); +spreadBool.valueOf(); // error, what were you thinking? var spreadStr = __assign({}, 'foo'); spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either -var spreadBool = __assign({}, true); -spreadBool.valueOf(); // error, what were you thinking? +// functions are skipped var spreadFunc = __assign({}, function () { }); spreadFunc(); // error, no call signature // write-only properties get skipped @@ -133,13 +136,14 @@ var C = (function () { var c = new C(); var spreadC = __assign({}, c); spreadC.m(); // error 'm' is not in '{ ... c }' -var callableConstructableSpread; -callableConstructableSpread(12); // error, no call signature -new callableConstructableSpread(12); // error, no construct signature -function override(initial, override, t, v) { - // { ... T & V } is not assignable to { ... T & U } - var tvs; - var mistake = tvs; - // { ...U } is not assignable to U +// generics +function f(t, u) { + return __assign({}, t, u, { id: 'id' }); +} +function override(initial, override) { return __assign({}, initial, override); } +var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false }); +var overlap = f({ a: 1 }, { a: 2, b: 'extra' }); +var overlapConflict = f({ a: 1 }, { a: 'mismatch' }); +var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' }); diff --git a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt index 41651fb1d1c8e..987172ef867bf 100644 --- a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt +++ b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt @@ -1,26 +1,36 @@ +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,15): error TS2304: Cannot find name 'o'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,18): error TS1109: Expression expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,15): error TS1109: Expression expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,16): error TS2304: Cannot find name 'o'. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,15): error TS2304: Cannot find name 'matchMedia'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,28): error TS1005: ',' expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,31): error TS1128: Declaration or statement expected. +tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,13): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,16): error TS2304: Cannot find name 'get'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error TS1005: ',' expected. -==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (9 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (13 errors) ==== let o7 = { ...o? }; + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. ~ !!! error TS2304: Cannot find name 'o'. ~ !!! error TS1109: Expression expected. let o8 = { ...*o }; + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. ~ !!! error TS1109: Expression expected. ~ !!! error TS2304: Cannot find name 'o'. let o9 = { ...matchMedia() { }}; + ~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. ~~~~~~~~~~ !!! error TS2304: Cannot find name 'matchMedia'. ~ @@ -28,6 +38,8 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error T ~ !!! error TS1128: Declaration or statement expected. let o10 = { ...get x() { return 12; }}; + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. ~~~ !!! error TS2304: Cannot find name 'get'. ~ diff --git a/tests/cases/conformance/types/spread/interfaceSpread.ts b/tests/cases/conformance/types/spread/interfaceSpread.ts deleted file mode 100644 index a92a188e1a884..0000000000000 --- a/tests/cases/conformance/types/spread/interfaceSpread.ts +++ /dev/null @@ -1,8 +0,0 @@ -interface Congealed { - ...T - ...U -} - -let sandwich: Congealed<{jam: number }, { peanutButter: number }>; -sandwich.jam; -sandwich.peanutButter; diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index daadb1e3270e5..3336196e136c3 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -35,13 +35,8 @@ let getter: { a: number, c: number } = { ...op, c: 7 } getter.a = 12; -// null, undefined, functions and primitives result in { } -let spreadNull = { ...null }; -let spreadUndefind = { ...undefined }; -let spreadNum = { ...12 }; -let spreadBool = { ...false }; +// functions result in { } let spreadFunc = { ...(function () { }) }; -let spreadStr = { ...'foo' }; // methods are not enumerable class C { p = 1; m() { } } @@ -80,19 +75,3 @@ let computedAfter: { a: number, b: string, "at the end": number } = let a = 12; let shortCutted: { a: number, b: string } = { ...o, a } -// generics -function f(t: T, u: U): { ...T, ...U, id: string } { - return { ...t, ...u, id: 'id' }; -} -let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = - f({ a: 1, b: 'yes' }, { c: 'no', d: false }) -let overlap: { id: string, a: number, b: string } = - f({ a: 1 }, { a: 2, b: 'extra' }) -let overlapConflict: { id:string, a: string } = - f({ a: 1 }, { a: 'mismatch' }) -let overwriteId: { id: string, a: number, c: number, d: string } = - f({ a: 1, id: true }, { c: 1, d: 'no' }) - -class D { m() { }; q = 2; } -let classesAreWrong: { id: string, ...C, ...D } = - f(new C(), new D()) diff --git a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts b/tests/cases/conformance/types/spread/objectSpreadGeneric.ts deleted file mode 100644 index 6f22358b7e25a..0000000000000 --- a/tests/cases/conformance/types/spread/objectSpreadGeneric.ts +++ /dev/null @@ -1,72 +0,0 @@ -function f(t: T, u: U, v: V): void { - let o: { ...T, ...U, ...V }; - let uus: { ...U, ...U}; - let us: { ...U }; - const same: { ...T, ...U, ...V } = o; // ok - uus = us; // ok, multiple spreads are equivalent to a single one - us = uus; // ok, multiple spreads are equivalent to a single one - us = u; // ok, type has at least all the properties of the spread - u = us; // error, might be missing a ton of stuff - const reversed: { ...V, ...U, ...T } = o; // error, reversed - const reversed2: { ...U, ...T, ...V } = o; // error, U and T are still reversed - const missingT: { ...U, ...V } = o; // error, missing T - const missingU: { ...T, ...V } = o; // error, missing U - const missingV: { ...T, ...U } = o; // error, missing V - const atEnd: { ...T, ...U, second: string } = { ...t, ...u, second: 'foo' }; // ok - const atBeginning: { first: string, ...T, ...U, } = { first: 'foo', ...t, ...u }; // error, not assignable - - const emptyTarget: { } = { ...t, ...u } // ok - const emptySource: { ...T, ...U } = { }; // error, {} is not assignable to U (or T) - - // error, { sn?: boolean } ...T ... { sn?: number | string } is not assignable to - // T ... { sn?: number | string | boolean } - let optionalNumber: { sn?: number }; - let optionalString: { sn?: string }; - let optionalBoolean: { sn?: boolean }; - const unionCutoff: { ...T, sn?: number | string | boolean } = - { ...optionalBoolean, ...t, ...optionalString, ...optionalNumber } - unionCutoff.sn; // ok - const optionalCutoff = { ...t, ...optionalNumber }; // ok - optionalCutoff.sn; // ok - - const interspersed: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable - const interspersedMissingU: { first: string, second: string, ...T, third: string } = - { first: '1', ...t, second: '2', ...u, third: '3' }; // error, 'U' is missing - const interspersedOrder1: { first: string, ...T, second: string, ...U, third: string, secondsecond: string } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable - const interspersedOrder2: { first: string, second: string, secondsecond: string, third: string, ...T, ...U } = - { first: '1', ...t, second: '2', ...u, third: '3', secondsecond: 'false' }; // error, not assignable - - - const mismatchFirst: { first: string, ...T, second: string, ...U, third: string } = - { firrrrrrst: '1', ...t, second: '2', ...u, third: '3' }; // error, not assignable - const mismatchSecond: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, ssssssssecond: '2', ...u, third: '3' }; // error, not assignable - const mismatchLast: { first: string, ...T, second: string, ...U, third: string } = - { first: '1', ...t, second: '2', ...u, thirrrrrrrd: '3' }; // error, not assignable -} - -function indexAccessedTest(t: T, u: U, key1: K, key2: J) { - let k1: { ...keyof T }; - let k2: { ...keyof U }; - let k3: { ...K }; - let k4: { ...J }; - k1 = k1; // ok - k2 = k2; // ok - k1 = k2; // error - k2 = k1; // error - k3 = k3; // ok - k4 = k4; // ok - k1 = k3; // error - k3 = k1; // error - k2 = k4; // error - k4 = k2; // error - - let i1: { ...T[K] }; - let i2: { ...U[J] }; - i1 = i1; // ok - i2 = i2; // ok - i1 = i2; // error - i2 = i1; // error -} diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts index 8c9194d2d4cdc..ae46f2547d54c 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -1,25 +1,16 @@ -class C { - a: number; - c: boolean; -} -// index signatures are not allowed in object literals with spread types -let c: { ...C, b: string, c?: string, [n: number]: string }; -let n: number = c.a; -let s: string = c[12]; interface Indexed { [n: string]: number; a: number; } -let i: { ...Indexed, b: number }; -n = i[101]; -n = i.b; interface Indexed2 { [n: string]: boolean; c: boolean; } -let ii: { ...Indexed, ...Indexed2, b: boolean, d: number }; -let nb: number | boolean = ii[1001]; - -function f(t: T) { - let i: { ...T, [n: number]: string }; -} +let indexed: Indexed; +let indexed2: Indexed2; +let i = { ...indexed, b: 11 }; +// only indexed has indexer, so i[101]: any +i[101]; +let ii = { ...indexed, ...indexed2 }; +// both have indexer, so i[1001]: number | boolean +ii[1001]; diff --git a/tests/cases/conformance/types/spread/objectSpreadInference.ts b/tests/cases/conformance/types/spread/objectSpreadInference.ts deleted file mode 100644 index 9608f0a16cb95..0000000000000 --- a/tests/cases/conformance/types/spread/objectSpreadInference.ts +++ /dev/null @@ -1,19 +0,0 @@ -interface Result { - t: T; - u: U; - v: V; -} -declare function infer(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V }; -declare function infer2(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V }; -function generic(w: W, x: X, y: Y) { - // should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter - return infer({ ...w, ...x, a: y, b: "different type" }); -} -let b: { b: number }; -let c: { c: number }; -// can only infer { t: {}, u: {}, v: {} } -let i1 = infer({ ...b, ...c, a: 12 }); -// can only infer { t: {}, u: {}, v: {} } -let i2 = infer2({ ...b, ...c, a: 12 }); -// can only infer { t: {}, u: {}, v: {} } -let i3 = generic(b, c, { a: 12 }); diff --git a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts b/tests/cases/conformance/types/spread/objectSpreadIntersection.ts deleted file mode 100644 index 3bedacca89fac..0000000000000 --- a/tests/cases/conformance/types/spread/objectSpreadIntersection.ts +++ /dev/null @@ -1,36 +0,0 @@ -function iteratedUnionIntersection(t: T, u: U, v: V): void { - let tu: T | U; - let uv: U & V; - let result = { ...tu, ...uv, id: 'foo' }; - let assignable: { ...(T | U), ...(U & V), id: string } = result; -} -// concrete types work -interface A1 { a: number } -interface A2 { a: string } -interface B1 { b: number } -interface B2 { b: string } -let a12: A1 & A2; -let b12: B1 & B2; -let result = { ...a12, ...b12 }; -let sn: number & string = result.a; -sn = result.b; -let assignable: { ...(A1 & A2), ...(B1 & B2) } = result; - -function tripleIntersection(t: T, u: U, v: V): void { - let tuv: T & U & V; - let result = { ...tuv, id: 'bar' }; - let assignable: { ...(T & U & V), id: string } = result; -} -function iteratedDoubleIntersection(t: T, u: U, v: V): void { - let tu: T & U; - let uv: U & V; - let result = { ...tu, ...uv, id: 'baz' }; - let assignable: { ...(T & U), ...(U & V), id: string } = result; -} -function iteratedIntersectionUnion(t: T, u: U, v: V): void { - let tu: T & U; - let uv: U | V; - let result = { ...tu, ...uv, id: 'qux' }; - let assignable: { ...(T & U), ...(U | V), id: string } = result; -} - diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 146ab072bbf17..3cd819d061350 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -8,7 +8,9 @@ class PrivateOptionalX { class PublicX { public x: number; } -let o2: { ...PublicX, ...PrivateOptionalX }; +let publicX: PublicX; +let privateOptionalX: PrivateOptionalX; +let o2 = { ...publicX, ...privateOptionalX }; let sn: number = o2.x; // error, x is private let optionalString: { sn?: string }; let optionalNumber: { sn?: number }; @@ -18,30 +20,27 @@ let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumbe // assignability as target interface Bool { b: boolean }; interface Str { s: string }; -let spread: { ...Bool, ...Str } = { s: 'foo' }; // error, missing 'b' -let b: Bool; +let spread = { ...{ b: true }, ...{s: "foo" } }; +spread = { s: "foo" }; // error, missing 'b' +let b = { b: false }; spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// null and undefined are just skipped -let spreadNull = { ...null } -spreadNull.null; -let spreadUndefined = { ...undefined } -spreadUndefined.undefined; - -// primitives and functions are skipped +// null, undefined and primitives are not allowed +let spreadNull = { ...null }; +let spreadUndefind = { ...undefined }; let spreadNum = { ...12 }; -spreadNum.toFixed(); // error, no methods from number let spreadSum = { ...1 + 1 }; spreadSum.toFixed(); // error, no methods from number +let spreadBool = { ...false }; +spreadBool.valueOf(); // error, what were you thinking? let spreadStr = { ...'foo' }; spreadStr.length; // error, no 'length' spreadStr.charAt(1); // error, no methods either -let spreadBool = { ...true }; -spreadBool.valueOf(); // error, what were you thinking? +// functions are skipped let spreadFunc = { ...function () { } } spreadFunc(); // error, no call signature @@ -55,14 +54,18 @@ let c: C = new C() let spreadC = { ...c } spreadC.m(); // error 'm' is not in '{ ... c }' -let callableConstructableSpread: { ...PublicX, (n: number): number, new (p: number) }; -callableConstructableSpread(12); // error, no call signature -new callableConstructableSpread(12); // error, no construct signature - -function override(initial: U, override: U, t: T, v: V): U { - // { ... T & V } is not assignable to { ... T & U } - let tvs: { ...T & V }; - let mistake: { ...T & U } = tvs; - // { ...U } is not assignable to U +// generics +function f(t: T, u: U) { + return { ...t, ...u, id: 'id' }; +} +function override(initial: U, override: U): U { return { ...initial, ...override }; } +let exclusive: { id: string, a: number, b: string, c: string, d: boolean } = + f({ a: 1, b: 'yes' }, { c: 'no', d: false }) +let overlap: { id: string, a: number, b: string } = + f({ a: 1 }, { a: 2, b: 'extra' }) +let overlapConflict: { id:string, a: string } = + f({ a: 1 }, { a: 'mismatch' }) +let overwriteId: { id: string, a: number, c: number, d: string } = + f({ a: 1, id: true }, { c: 1, d: 'no' }) diff --git a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts b/tests/cases/conformance/types/spread/objectSpreadScenarios.ts deleted file mode 100644 index 1db930cb71c51..0000000000000 --- a/tests/cases/conformance/types/spread/objectSpreadScenarios.ts +++ /dev/null @@ -1,17 +0,0 @@ -interface A1 { a: boolean } -interface B1 { b: number }; -function override(initial: U, override: U): { ...U, ...U } { - return { ...initial, ...override }; -} -function update(this: { u: { ...U } }, override: U): void { - this.u = { ...this.u, ...override }; -} -function mixin(one: T, two: U): { ...T, ...U } { - return { ...one, ...two }; -} -let a1: A1 = { a: true }; -let b1: B1 = { b: 101 }; -a1 = override(a1, { a: false }); -let host = { u: a1, update }; -host.update({ a: false }); -let mixed = mixin(a1, b1); diff --git a/tests/cases/conformance/types/spread/objectSpreadUnion.ts b/tests/cases/conformance/types/spread/objectSpreadUnion.ts deleted file mode 100644 index cd490d76bdaf4..0000000000000 --- a/tests/cases/conformance/types/spread/objectSpreadUnion.ts +++ /dev/null @@ -1,23 +0,0 @@ -// concrete types work -interface A1 { a: number } -interface A2 { a: string } -let a12: A1 | A2; -let result = { ...a12 }; -let sn: number | string = result.a; -let assignable: { ...(A1 | A2) } = result; - -function tripleUnion(t: T, u: U, v: V): void { - let tuv: T | U | V; - let result = { ...tuv, id: 'foo' }; - let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result; - let assignable: { ...(T | U | V), id: string } = result; -} -function iteratedDoubleUnion(t: T, u: U, v: V): void { - let tu: T | U; - let uv: U | V; - let result = { ...tu, ...uv, id: 'bar' }; - let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string }; - let assignable: { ...(T | U), ...(U | V), id: string } = result; -} - - diff --git a/tests/cases/fourslash/findAllRefsForObjectSpread.ts b/tests/cases/fourslash/findAllRefsForObjectSpread.ts index 650324a5d8467..05c83491f6651 100644 --- a/tests/cases/fourslash/findAllRefsForObjectSpread.ts +++ b/tests/cases/fourslash/findAllRefsForObjectSpread.ts @@ -2,7 +2,9 @@ ////interface A1 { [|a|]: string }; ////interface A2 { [|a|]?: number }; -////let a12: { ...A1, ...A2 }; +////let a1: A1; +////let a2: A2; +////let a12 = { ...a1, ...a2 }; ////a12.[|a|]; const ranges = test.ranges(); // members of spread types only refer to themselves and the resulting property diff --git a/tests/cases/fourslash/goToDefinitionObjectSpread.ts b/tests/cases/fourslash/goToDefinitionObjectSpread.ts index 64623c36cb76b..b23d0a8044832 100644 --- a/tests/cases/fourslash/goToDefinitionObjectSpread.ts +++ b/tests/cases/fourslash/goToDefinitionObjectSpread.ts @@ -2,6 +2,8 @@ ////interface A1 { /*1*/a: number }; ////interface A2 { /*2*/a?: number }; -////let a12: { ...A1, ...A2 }; +////let a1: A1; +////let a2: A2; +////let a12 = { ...a1, ...a2 }; ////a12.a/*3*/; verify.goToDefinition('3', [ '1', '2' ]); diff --git a/tests/cases/fourslash/renameObjectSpread.ts b/tests/cases/fourslash/renameObjectSpread.ts index a2c640361e59c..eba148c0e3944 100644 --- a/tests/cases/fourslash/renameObjectSpread.ts +++ b/tests/cases/fourslash/renameObjectSpread.ts @@ -2,7 +2,9 @@ ////interface A1 { [|a|]: number }; ////interface A2 { [|a|]?: number }; -////let a12: { ...A1, ...A2 }; +////let a1: A1; +////let a2: A2; +////let a12 = { ...a1, ...a2 }; ////a12.[|a|]; const ranges = test.ranges(); verify.assertHasRanges(ranges); From 7a2c7ad37420ad8f11652a6b87116c1b20fca802 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Nov 2016 09:41:31 -0700 Subject: [PATCH 64/85] Spread handles index signatures from singleton spreads I broke it when simplifying the logic earlier. --- src/compiler/checker.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 872aad6b046b7..3475a9d52c6f7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5888,8 +5888,17 @@ namespace ts { Debug.assert(!!(left.flags & TypeFlags.Object) && !!(right.flags & TypeFlags.Object), "Only object types may be spread."); const members = createMap(); const skippedPrivateMembers = createMap(); - const stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); - const numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); + let stringIndexInfo: IndexInfo; + let numberIndexInfo: IndexInfo; + if (left === emptyObjectType) { + // for the first spread element, left === emptyObjectType, so take the right's string indexer + stringIndexInfo = getIndexInfoOfType(right, IndexKind.String); + numberIndexInfo = getIndexInfoOfType(right, IndexKind.Number); + } + else { + stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); + numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); + } const isFromSpread = right.symbol !== symbol; for (const rightProp of getPropertiesOfType(right)) { From 7ed52044d11fb30e396a171847faee0fa1d5ce42 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Nov 2016 10:54:07 -0700 Subject: [PATCH 65/85] Update objectRestAssignment test and baselines --- .../reference/objectRestAssignment.js | 10 ++--- .../reference/objectRestAssignment.symbols | 40 +++++++++---------- .../reference/objectRestAssignment.types | 28 ++++++------- 3 files changed, 36 insertions(+), 42 deletions(-) diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js index 7ecd54c51527a..20f87ff837564 100644 --- a/tests/baselines/reference/objectRestAssignment.js +++ b/tests/baselines/reference/objectRestAssignment.js @@ -1,9 +1,8 @@ //// [objectRestAssignment.ts] -let x; -let ka; -let nested; -let other; -let rest; +let ka: any; +let nested: { ki }; +let other: number; +let rest: { }; let complex: { x: { ka, ki }, y: number }; ({x: { ka, ...nested }, y: other, ...rest} = complex); @@ -15,7 +14,6 @@ var __rest = (this && this.__rest) || function (s, e) { t[p] = s[p]; return t; }; -var x; var ka; var nested; var other; diff --git a/tests/baselines/reference/objectRestAssignment.symbols b/tests/baselines/reference/objectRestAssignment.symbols index 3c54290b5954b..38127dbee2d2c 100644 --- a/tests/baselines/reference/objectRestAssignment.symbols +++ b/tests/baselines/reference/objectRestAssignment.symbols @@ -1,30 +1,28 @@ === tests/cases/conformance/types/rest/objectRestAssignment.ts === -let x; ->x : Symbol(x, Decl(objectRestAssignment.ts, 0, 3)) +let ka: any; +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 0, 3)) -let ka; ->ka : Symbol(ka, Decl(objectRestAssignment.ts, 1, 3)) +let nested: { ki }; +>nested : Symbol(nested, Decl(objectRestAssignment.ts, 1, 3)) +>ki : Symbol(ki, Decl(objectRestAssignment.ts, 1, 13)) -let nested; ->nested : Symbol(nested, Decl(objectRestAssignment.ts, 2, 3)) +let other: number; +>other : Symbol(other, Decl(objectRestAssignment.ts, 2, 3)) -let other; ->other : Symbol(other, Decl(objectRestAssignment.ts, 3, 3)) - -let rest; ->rest : Symbol(rest, Decl(objectRestAssignment.ts, 4, 3)) +let rest: { }; +>rest : Symbol(rest, Decl(objectRestAssignment.ts, 3, 3)) let complex: { x: { ka, ki }, y: number }; ->complex : Symbol(complex, Decl(objectRestAssignment.ts, 5, 3)) ->x : Symbol(x, Decl(objectRestAssignment.ts, 5, 14)) ->ka : Symbol(ka, Decl(objectRestAssignment.ts, 5, 19)) ->ki : Symbol(ki, Decl(objectRestAssignment.ts, 5, 23)) ->y : Symbol(y, Decl(objectRestAssignment.ts, 5, 29)) +>complex : Symbol(complex, Decl(objectRestAssignment.ts, 4, 3)) +>x : Symbol(x, Decl(objectRestAssignment.ts, 4, 14)) +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 4, 19)) +>ki : Symbol(ki, Decl(objectRestAssignment.ts, 4, 23)) +>y : Symbol(y, Decl(objectRestAssignment.ts, 4, 29)) ({x: { ka, ...nested }, y: other, ...rest} = complex); ->x : Symbol(x, Decl(objectRestAssignment.ts, 6, 2)) ->ka : Symbol(ka, Decl(objectRestAssignment.ts, 6, 6)) ->y : Symbol(y, Decl(objectRestAssignment.ts, 6, 23)) ->other : Symbol(other, Decl(objectRestAssignment.ts, 3, 3)) ->complex : Symbol(complex, Decl(objectRestAssignment.ts, 5, 3)) +>x : Symbol(x, Decl(objectRestAssignment.ts, 5, 2)) +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 5, 6)) +>y : Symbol(y, Decl(objectRestAssignment.ts, 5, 23)) +>other : Symbol(other, Decl(objectRestAssignment.ts, 2, 3)) +>complex : Symbol(complex, Decl(objectRestAssignment.ts, 4, 3)) diff --git a/tests/baselines/reference/objectRestAssignment.types b/tests/baselines/reference/objectRestAssignment.types index 5af3e5872b95e..a4d88f89bb276 100644 --- a/tests/baselines/reference/objectRestAssignment.types +++ b/tests/baselines/reference/objectRestAssignment.types @@ -1,18 +1,16 @@ === tests/cases/conformance/types/rest/objectRestAssignment.ts === -let x; ->x : any - -let ka; +let ka: any; >ka : any -let nested; ->nested : any +let nested: { ki }; +>nested : { ki: any; } +>ki : any -let other; ->other : any +let other: number; +>other : number -let rest; ->rest : any +let rest: { }; +>rest : {} let complex: { x: { ka, ki }, y: number }; >complex : { x: { ka: any; ki: any; }; y: number; } @@ -24,13 +22,13 @@ let complex: { x: { ka, ki }, y: number }; ({x: { ka, ...nested }, y: other, ...rest} = complex); >({x: { ka, ...nested }, y: other, ...rest} = complex) : { x: { ka: any; ki: any; }; y: number; } >{x: { ka, ...nested }, y: other, ...rest} = complex : { x: { ka: any; ki: any; }; y: number; } ->{x: { ka, ...nested }, y: other, ...rest} : { x: { ka: any; }; y: any; } ->x : { ka: any; } ->{ ka, ...nested } : { ka: any; } +>{x: { ka, ...nested }, y: other, ...rest} : { x: { ki: any; ka: any; }; y: number; } +>x : { ki: any; ka: any; } +>{ ka, ...nested } : { ki: any; ka: any; } >ka : any >nested : any ->y : any ->other : any +>y : number +>other : number >rest : any >complex : { x: { ka: any; ki: any; }; y: number; } From 14f8b9990f7307484ab317c6b9016d50a26db1c7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Nov 2016 13:33:16 -0700 Subject: [PATCH 66/85] Update objectRestAssignment test Missed previously, just got the baselines --- .../cases/conformance/types/rest/objectRestAssignment.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/cases/conformance/types/rest/objectRestAssignment.ts b/tests/cases/conformance/types/rest/objectRestAssignment.ts index 19be53d29a3b3..4c8da304bc3c3 100644 --- a/tests/cases/conformance/types/rest/objectRestAssignment.ts +++ b/tests/cases/conformance/types/rest/objectRestAssignment.ts @@ -1,7 +1,6 @@ -let x; -let ka; -let nested; -let other; -let rest; +let ka: any; +let nested: { ki }; +let other: number; +let rest: { }; let complex: { x: { ka, ki }, y: number }; ({x: { ka, ...nested }, y: other, ...rest} = complex); From c9c5f49a24c0ea8a56af4797f710de3fec0ebd3a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 3 Nov 2016 13:36:35 -0700 Subject: [PATCH 67/85] Improve readability of ES next destructuring emit --- src/compiler/transformers/destructuring.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index bac8e99420115..4c9682c10b646 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -311,7 +311,10 @@ namespace ts { for (let i = 0; i < properties.length; i++) { const p = properties[i]; if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - if (!transformRest || p.transformFlags & TransformFlags.ContainsSpreadExpression) { + if (transformRest && !(p.transformFlags & TransformFlags.ContainsSpreadExpression)) { + es2015.push(p); + } + else { if (es2015.length) { emitRestAssignment(es2015, value, location, target); es2015 = []; @@ -321,9 +324,6 @@ namespace ts { // Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p); } - else { - es2015.push(p); - } } else if (i === properties.length - 1 && p.kind === SyntaxKind.SpreadElementExpression) { Debug.assert((p as SpreadElementExpression).expression.kind === SyntaxKind.Identifier); @@ -460,7 +460,11 @@ namespace ts { name); emitBindingElement(element, restCall); } - else if (!transformRest || element.transformFlags & TransformFlags.ContainsSpreadExpression) { + else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) { + // do not emit until we have a complete bundle of ES2015 syntax + es2015.push(element); + } + else { if (es2015.length) { emitRestAssignment(es2015, value, target, target); es2015 = []; @@ -469,10 +473,6 @@ namespace ts { const propName = element.propertyName || element.name; emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); } - else { - // do not emit until we have a complete bundle of ES2015 syntax - es2015.push(element); - } } if (es2015.length) { emitRestAssignment(es2015, value, target, target); From 71f3157a35cacd404371d6020929a1299d959f15 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Nov 2016 09:03:03 -0700 Subject: [PATCH 68/85] Address PR comments 1. Remove extra line in __rest shim. 2. Improve __rest vs __assign check for destructuring assignment. --- src/compiler/binder.ts | 12 ++++++++++-- src/compiler/emitter.ts | 1 - 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index a4d9a5a30ed02..7aa27e520d3e2 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1935,10 +1935,18 @@ namespace ts { case SyntaxKind.SpreadElementExpression: case SyntaxKind.JsxSpreadAttribute: let root = container; - while (root && root.kind !== SyntaxKind.BinaryExpression) { + let hasRest = false; + while (root.parent) { + if (root.kind === SyntaxKind.ObjectLiteralExpression && + root.parent.kind === SyntaxKind.BinaryExpression && + (root.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && + (root.parent as BinaryExpression).left === root) { + hasRest = true; + break; + } root = root.parent; } - emitFlags |= root && isDestructuringAssignment(root) ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute; + emitFlags |= hasRest ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute; return; case SyntaxKind.CallSignature: diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index c89fa1f155043..9885ea9c79179 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -45,7 +45,6 @@ var __assign = (this && this.__assign) || Object.assign || function(t) { const restHelper = ` var __rest = (this && this.__rest) || function (s, e) { var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p)) t[p] = s[p]; return t; From cc342d12e7c63e4abb2725ee81d747672cefae46 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Nov 2016 11:06:56 -0700 Subject: [PATCH 69/85] Move convertForOf to factory for esnext and es2015 Saves a lot of duplicated code --- src/compiler/factory.ts | 190 ++++++++++++++++++++++++++++ src/compiler/transformers/es2015.ts | 166 +----------------------- src/compiler/transformers/esnext.ts | 87 +------------ 3 files changed, 192 insertions(+), 251 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index c7fe7d7057499..7f758f7079479 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3055,4 +3055,194 @@ namespace ts { function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); } + + export function convertForOf(node: ForOfStatement, convertedLoopBodyStatements: Statement[], + visitor: (node: Node) => VisitResult, + enableSubstitutionsForBlockScopedBindings: () => void, + context: TransformationContext, + convertObjectRest?: boolean): ForStatement | ForOfStatement { + // The following ES6 code: + // + // for (let v of expr) { } + // + // should be emitted as + // + // for (var _i = 0, _a = expr; _i < _a.length; _i++) { + // var v = _a[_i]; + // } + // + // where _a and _i are temps emitted to capture the RHS and the counter, + // respectively. + // When the left hand side is an expression instead of a let declaration, + // the "let v" is not emitted. + // When the left hand side is a let/const, the v is renamed if there is + // another v in scope. + // Note that all assignments to the LHS are emitted in the body, including + // all destructuring. + // Note also that because an extra statement is needed to assign to the LHS, + // for-of bodies are always emitted as blocks. + + const expression = visitNode(node.expression, visitor, isExpression); + const initializer = node.initializer; + const statements: Statement[] = []; + + // In the case where the user wrote an identifier as the RHS, like this: + // + // for (let v of arr) { } + // + // we don't want to emit a temporary variable for the RHS, just use it directly. + const counter = convertObjectRest ? undefined : createLoopVariable(); + const rhsReference = expression.kind === SyntaxKind.Identifier + ? createUniqueName((expression).text) + : createTempVariable(/*recordTempVariable*/ undefined); + const elementAccess = convertObjectRest ? rhsReference : createElementAccess(rhsReference, counter); + + // Initialize LHS + // var v = _a[_i]; + if (isVariableDeclarationList(initializer)) { + if (initializer.flags & NodeFlags.BlockScoped) { + enableSubstitutionsForBlockScopedBindings(); + } + + const firstOriginalDeclaration = firstOrUndefined(initializer.declarations); + if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { + // This works whether the declaration is a var, let, or const. + // It will use rhsIterationValue _a[_i] as the initializer. + const declarations = flattenVariableDestructuring( + firstOriginalDeclaration, + elementAccess, + visitor, + /*recordTempVariable*/ undefined, + convertObjectRest + ); + + const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); + setOriginalNode(declarationList, initializer); + + // Adjust the source map range for the first declaration to align with the old + // emitter. + const firstDeclaration = declarations[0]; + const lastDeclaration = lastOrUndefined(declarations); + setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end)); + + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + declarationList + ) + ); + } + else { + // The following call does not include the initializer, so we have + // to emit it separately. + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + setOriginalNode( + createVariableDeclarationList([ + createVariableDeclaration( + firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), + /*type*/ undefined, + createElementAccess(rhsReference, counter) + ) + ], /*location*/ moveRangePos(initializer, -1)), + initializer + ), + /*location*/ moveRangeEnd(initializer, -1) + ) + ); + } + } + else { + // Initializer is an expression. Emit the expression in the body, so that it's + // evaluated on every iteration. + const assignment = createAssignment(initializer, elementAccess); + if (isDestructuringAssignment(assignment)) { + // This is a destructuring pattern, so we flatten the destructuring instead. + statements.push( + createStatement( + flattenDestructuringAssignment( + context, + assignment, + /*needsValue*/ false, + context.hoistVariableDeclaration, + visitor, + convertObjectRest + ) + ) + ); + } + else { + // Currently there is not way to check that assignment is binary expression of destructing assignment + // so we have to cast never type to binaryExpression + (assignment).end = initializer.end; + statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1))); + } + } + + let bodyLocation: TextRange; + let statementsLocation: TextRange; + if (convertedLoopBodyStatements) { + addRange(statements, convertedLoopBodyStatements); + } + else { + const statement = visitNode(node.statement, visitor, isStatement); + if (isBlock(statement)) { + addRange(statements, statement.statements); + bodyLocation = statement; + statementsLocation = statement.statements; + } + else { + statements.push(statement); + } + } + + // The old emitter does not emit source maps for the expression + setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); + + // The old emitter does not emit source maps for the block. + // We add the location to preserve comments. + const body = createBlock( + createNodeArray(statements, /*location*/ statementsLocation), + /*location*/ bodyLocation + ); + + setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); + + let forStatement: ForStatement | ForOfStatement; + if(convertObjectRest) { + + forStatement = createForOf( + createVariableDeclarationList([ + createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression) + ], /*location*/ node.expression), + node.expression, + body, + /*location*/ node + ); + } + else { + forStatement = createFor( + setEmitFlags( + createVariableDeclarationList([ + createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), + createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression) + ], /*location*/ node.expression), + EmitFlags.NoHoisting + ), + createLessThan( + counter, + createPropertyAccess(rhsReference, "length"), + /*location*/ node.expression + ), + createPostfixIncrement(counter, /*location*/ node.expression), + body, + /*location*/ node + ); + } + + // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. + setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); + return forStatement; + } } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index e262b413b4c72..76ea6b2ddd0b8 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -1926,171 +1926,7 @@ namespace ts { } function convertForOfToFor(node: ForOfStatement, convertedLoopBodyStatements: Statement[]): ForStatement { - // The following ES6 code: - // - // for (let v of expr) { } - // - // should be emitted as - // - // for (var _i = 0, _a = expr; _i < _a.length; _i++) { - // var v = _a[_i]; - // } - // - // where _a and _i are temps emitted to capture the RHS and the counter, - // respectively. - // When the left hand side is an expression instead of a let declaration, - // the "let v" is not emitted. - // When the left hand side is a let/const, the v is renamed if there is - // another v in scope. - // Note that all assignments to the LHS are emitted in the body, including - // all destructuring. - // Note also that because an extra statement is needed to assign to the LHS, - // for-of bodies are always emitted as blocks. - - const expression = visitNode(node.expression, visitor, isExpression); - const initializer = node.initializer; - const statements: Statement[] = []; - - // In the case where the user wrote an identifier as the RHS, like this: - // - // for (let v of arr) { } - // - // we don't want to emit a temporary variable for the RHS, just use it directly. - const counter = createLoopVariable(); - const rhsReference = expression.kind === SyntaxKind.Identifier - ? createUniqueName((expression).text) - : createTempVariable(/*recordTempVariable*/ undefined); - - // Initialize LHS - // var v = _a[_i]; - if (isVariableDeclarationList(initializer)) { - if (initializer.flags & NodeFlags.BlockScoped) { - enableSubstitutionsForBlockScopedBindings(); - } - - const firstOriginalDeclaration = firstOrUndefined(initializer.declarations); - if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { - // This works whether the declaration is a var, let, or const. - // It will use rhsIterationValue _a[_i] as the initializer. - const declarations = flattenVariableDestructuring( - firstOriginalDeclaration, - createElementAccess(rhsReference, counter), - visitor - ); - - const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); - setOriginalNode(declarationList, initializer); - - // Adjust the source map range for the first declaration to align with the old - // emitter. - const firstDeclaration = declarations[0]; - const lastDeclaration = lastOrUndefined(declarations); - setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end)); - - statements.push( - createVariableStatement( - /*modifiers*/ undefined, - declarationList - ) - ); - } - else { - // The following call does not include the initializer, so we have - // to emit it separately. - statements.push( - createVariableStatement( - /*modifiers*/ undefined, - setOriginalNode( - createVariableDeclarationList([ - createVariableDeclaration( - firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), - /*type*/ undefined, - createElementAccess(rhsReference, counter) - ) - ], /*location*/ moveRangePos(initializer, -1)), - initializer - ), - /*location*/ moveRangeEnd(initializer, -1) - ) - ); - } - } - else { - // Initializer is an expression. Emit the expression in the body, so that it's - // evaluated on every iteration. - const assignment = createAssignment(initializer, createElementAccess(rhsReference, counter)); - if (isDestructuringAssignment(assignment)) { - // This is a destructuring pattern, so we flatten the destructuring instead. - statements.push( - createStatement( - flattenDestructuringAssignment( - context, - assignment, - /*needsValue*/ false, - hoistVariableDeclaration, - visitor - ) - ) - ); - } - else { - // Currently there is not way to check that assignment is binary expression of destructing assignment - // so we have to cast never type to binaryExpression - (assignment).end = initializer.end; - statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1))); - } - } - - let bodyLocation: TextRange; - let statementsLocation: TextRange; - if (convertedLoopBodyStatements) { - addRange(statements, convertedLoopBodyStatements); - } - else { - const statement = visitNode(node.statement, visitor, isStatement); - if (isBlock(statement)) { - addRange(statements, statement.statements); - bodyLocation = statement; - statementsLocation = statement.statements; - } - else { - statements.push(statement); - } - } - - // The old emitter does not emit source maps for the expression - setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); - - // The old emitter does not emit source maps for the block. - // We add the location to preserve comments. - const body = createBlock( - createNodeArray(statements, /*location*/ statementsLocation), - /*location*/ bodyLocation - ); - - setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); - - const forStatement = createFor( - setEmitFlags( - createVariableDeclarationList([ - createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), - createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression) - ], /*location*/ node.expression), - EmitFlags.NoHoisting - ), - createLessThan( - counter, - createPropertyAccess(rhsReference, "length"), - /*location*/ node.expression - ), - createPostfixIncrement(counter, /*location*/ node.expression), - body, - /*location*/ node - ); - - // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. - setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); - return forStatement; + return convertForOf(node, convertedLoopBodyStatements, visitor, enableSubstitutionsForBlockScopedBindings, context, /*transformRest*/ false); } /** diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index a85098f03b6d9..26864a123ea33 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -162,92 +162,7 @@ namespace ts { return visitEachChild(node, visitor, context); } - const expression = visitNode(node.expression, visitor, isExpression); - const statements: Statement[] = []; - const rhsReference = createTempVariable(/*recordTempVariable*/ undefined); - - // var { x, y } = _a, rest = __rest(_a, ["x", "y"]); - if (isVariableDeclarationList(initializer)) { - // This works whether the declaration is a var, let, or const. - // It will use rhsReference _a as the initializer. - const declarations = flattenVariableDestructuring( - initializer.declarations[0], - rhsReference, - visitor, - /*recordTempVariable*/ undefined, - /*transformRest*/ true, - ); - - const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer); - setOriginalNode(declarationList, initializer); - - // Adjust the source map range for the first declaration to align with the old - // emitter. - const firstDeclaration = declarations[0]; - const lastDeclaration = lastOrUndefined(declarations); - setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end)); - - statements.push( - createVariableStatement( - /*modifiers*/ undefined, - declarationList - ) - ); - } - else { - // Initializer is an object literal destructuring assignment. - // Emit the flattened assignments from the object literal expression in the body - const assignment = createAssignment(initializer, rhsReference); - statements.push( - createStatement( - flattenDestructuringAssignment( - context, - assignment, - /*needsValue*/ false, - hoistVariableDeclaration, - visitor, - /*transformRest*/ true - ) - ) - ); - } - - let bodyLocation: TextRange; - let statementsLocation: TextRange; - const statement = visitNode(node.statement, visitor, isStatement); - if (isBlock(statement)) { - addRange(statements, statement.statements); - bodyLocation = statement; - statementsLocation = statement.statements; - } - else { - statements.push(statement); - } - - // The old emitter does not emit source maps for the expression - setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); - - // The old emitter does not emit source maps for the block. - // We add the location to preserve comments. - const body = createBlock( - createNodeArray(statements, /*location*/ statementsLocation), - /*location*/ bodyLocation - ); - - setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); - - const forStatement = createForOf( - createVariableDeclarationList([ - createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression) - ], /*location*/ node.expression), - node.expression, - body, - /*location*/ node - ); - - // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. - setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps); - return forStatement; + return convertForOf(node, undefined, visitor, noop, context, /*transformRest*/ true); } function isRestBindingPattern(initializer: ForInitializer) { From 4337369ed4996856925c59fc43ccde201efaf316 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Nov 2016 11:07:18 -0700 Subject: [PATCH 70/85] Update improved baselines --- tests/baselines/reference/objectRestForOf.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/objectRestForOf.js b/tests/baselines/reference/objectRestForOf.js index 0a6e2dc40ed34..26ebd8f8229c5 100644 --- a/tests/baselines/reference/objectRestForOf.js +++ b/tests/baselines/reference/objectRestForOf.js @@ -30,14 +30,14 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; let array; -for (var _a of array) { - var { x } = _a, restOf = __rest(_a, ["x"]); +for (var array_1 of array) { + var { x } = array_1, restOf = __rest(array_1, ["x"]); [x, restOf]; } let xx; let rrestOff; -for (var _b of array) { - ({ x: xx } = _b, rrestOff = __rest(_b, ["x"])); +for (var array_2 of array) { + ({ x: xx } = array_2, rrestOff = __rest(array_2, ["x"])); [xx, rrestOff]; } for (const norest of array.map(a => (__assign({}, a, { x: 'a string' })))) { From 4c365bd76a6357f33a5f3f5345a2ed276d22149a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Nov 2016 13:56:28 -0700 Subject: [PATCH 71/85] Move transformFunctionBody to factory It is shared by es2015 and esNext transformers. This commit just adds a convertObjectRest flag to be passed on to flattenDestructuring functions, as well as adding necessary parameters to use the code outside a transformer. --- src/compiler/factory.ts | 345 ++++++++++++++++++++++++++++ src/compiler/transformers/es2015.ts | 338 +-------------------------- src/compiler/transformers/esnext.ts | 183 ++------------- 3 files changed, 367 insertions(+), 499 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 7f758f7079479..605725b89cf57 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3056,6 +3056,351 @@ namespace ts { return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); } + /** + * Transforms the body of a function-like node. + * + * @param node A function-like node. + */ + export function transformFunctionBody(node: FunctionLikeDeclaration, + visitor: (node: Node) => VisitResult, + currentSourceFile: SourceFile, + context: TransformationContext, + enableSubstitutionsForCapturedThis: () => void, + convertObjectRest?: boolean) { + let multiLine = false; // indicates whether the block *must* be emitted as multiple lines + let singleLine = false; // indicates whether the block *may* be emitted as a single line + let statementsLocation: TextRange; + let closeBraceLocation: TextRange; + + const statements: Statement[] = []; + const body = node.body; + let statementOffset: number; + + context.startLexicalEnvironment(); + if (isBlock(body)) { + // ensureUseStrict is false because no new prologue-directive should be added. + // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array + statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + } + + addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis); + addDefaultValueAssignmentsIfNeeded(statements, node, visitor, convertObjectRest); + addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); + + // If we added any generated statements, this must be a multi-line block. + if (!multiLine && statements.length > 0) { + multiLine = true; + } + + if (isBlock(body)) { + statementsLocation = body.statements; + addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); + + // If the original body was a multi-line block, this must be a multi-line block. + if (!multiLine && body.multiLine) { + multiLine = true; + } + } + else { + Debug.assert(node.kind === SyntaxKind.ArrowFunction); + + // To align with the old emitter, we use a synthetic end position on the location + // for the statement list we synthesize when we down-level an arrow function with + // an expression function body. This prevents both comments and source maps from + // being emitted for the end position only. + statementsLocation = moveRangeEnd(body, -1); + + const equalsGreaterThanToken = (node).equalsGreaterThanToken; + if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) { + if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) { + singleLine = true; + } + else { + multiLine = true; + } + } + + const expression = visitNode(body, visitor, isExpression); + const returnStatement = createReturn(expression, /*location*/ body); + setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); + statements.push(returnStatement); + + // To align with the source map emit for the old emitter, we set a custom + // source map location for the close brace. + closeBraceLocation = body; + } + + const lexicalEnvironment = context.endLexicalEnvironment(); + addRange(statements, lexicalEnvironment); + + // If we added any final generated statements, this must be a multi-line block + if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { + multiLine = true; + } + + const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); + if (!multiLine && singleLine) { + setEmitFlags(block, EmitFlags.SingleLine); + } + + if (closeBraceLocation) { + setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation); + } + + setOriginalNode(block, node.body); + return block; + } + + /** + * Adds a statement to capture the `this` of a function declaration if it is needed. + * + * @param statements The statements for the new function body. + * @param node A node. + */ + export function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node, enableSubstitutionsForCapturedThis: () => void): void { + if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { + captureThisForNode(statements, node, createThis(), enableSubstitutionsForCapturedThis); + } + } + + export function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, enableSubstitutionsForCapturedThis?: () => void, originalStatement?: Statement): void { + enableSubstitutionsForCapturedThis(); + const captureThisStatement = createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + "_this", + /*type*/ undefined, + initializer + ) + ]), + originalStatement + ); + + setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); + setSourceMapRange(captureThisStatement, node); + statements.push(captureThisStatement); + } + + /** + * Gets a value indicating whether we need to add default value assignments for a + * function-like node. + * + * @param node A function-like node. + */ + function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { + return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0; + } + + /** + * Adds statements to the body of a function-like node if it contains parameters with + * binding patterns or initializers. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + */ + export function addDefaultValueAssignmentsIfNeeded(statements: Statement[], + node: FunctionLikeDeclaration, + visitor: (node: Node) => VisitResult, + convertObjectRest: boolean): void { + if (!shouldAddDefaultValueAssignments(node)) { + return; + } + + for (const parameter of node.parameters) { + const { name, initializer, dotDotDotToken } = parameter; + + // A rest parameter cannot have a binding pattern or an initializer, + // so let's just ignore it. + if (dotDotDotToken) { + continue; + } + + if (isBindingPattern(name)) { + addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer, visitor, convertObjectRest); + } + else if (initializer) { + addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer, visitor); + } + } + } + + /** + * Adds statements to the body of a function-like node for parameters with binding patterns + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + * @param name The name of the parameter. + * @param initializer The initializer for the parameter. + */ + function addDefaultValueAssignmentForBindingPattern(statements: Statement[], + parameter: ParameterDeclaration, + name: BindingPattern, initializer: Expression, + visitor: (node: Node) => VisitResult, + convertObjectRest: boolean): void { + const temp = getGeneratedNameForNode(parameter); + + // In cases where a binding pattern is simply '[]' or '{}', + // we usually don't want to emit a var declaration; however, in the presence + // of an initializer, we must emit that expression to preserve side effects. + if (name.elements.length > 0) { + statements.push( + setEmitFlags( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + flattenParameterDestructuring(parameter, temp, visitor, convertObjectRest) + ) + ), + EmitFlags.CustomPrologue + ) + ); + } + else if (initializer) { + statements.push( + setEmitFlags( + createStatement( + createAssignment( + temp, + visitNode(initializer, visitor, isExpression) + ) + ), + EmitFlags.CustomPrologue + ) + ); + } + } + + /** + * Adds statements to the body of a function-like node for parameters with initializers. + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + * @param name The name of the parameter. + * @param initializer The initializer for the parameter. + */ + function addDefaultValueAssignmentForInitializer(statements: Statement[], + parameter: ParameterDeclaration, + name: Identifier, + initializer: Expression, + visitor: (node: Node) => VisitResult): void { + initializer = visitNode(initializer, visitor, isExpression); + const statement = createIf( + createStrictEquality( + getSynthesizedClone(name), + createVoidZero() + ), + setEmitFlags( + createBlock([ + createStatement( + createAssignment( + setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), + setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)), + /*location*/ parameter + ) + ) + ], /*location*/ parameter), + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + ), + /*elseStatement*/ undefined, + /*location*/ parameter + ); + statement.startsOnNewLine = true; + setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue); + statements.push(statement); + } + + /** + * Gets a value indicating whether we need to add statements to handle a rest parameter. + * + * @param node A ParameterDeclaration node. + * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is + * part of a constructor declaration with a + * synthesized call to `super` + */ + function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) { + return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper; + } + + /** + * Adds statements to the body of a function-like node if it contains a rest parameter. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is + * part of a constructor declaration with a + * synthesized call to `super` + */ + export function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void { + const parameter = lastOrUndefined(node.parameters); + if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { + return; + } + + // `declarationName` is the name of the local declaration for the parameter. + const declarationName = getMutableClone(parameter.name); + setEmitFlags(declarationName, EmitFlags.NoSourceMap); + + // `expressionName` is the name of the parameter used in expressions. + const expressionName = getSynthesizedClone(parameter.name); + const restIndex = node.parameters.length - 1; + const temp = createLoopVariable(); + + // var param = []; + statements.push( + setEmitFlags( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + declarationName, + /*type*/ undefined, + createArrayLiteral([]) + ) + ]), + /*location*/ parameter + ), + EmitFlags.CustomPrologue + ) + ); + + // for (var _i = restIndex; _i < arguments.length; _i++) { + // param[_i - restIndex] = arguments[_i]; + // } + const forStatement = createFor( + createVariableDeclarationList([ + createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) + ], /*location*/ parameter), + createLessThan( + temp, + createPropertyAccess(createIdentifier("arguments"), "length"), + /*location*/ parameter + ), + createPostfixIncrement(temp, /*location*/ parameter), + createBlock([ + startOnNewLine( + createStatement( + createAssignment( + createElementAccess( + expressionName, + createSubtract(temp, createLiteral(restIndex)) + ), + createElementAccess(createIdentifier("arguments"), temp) + ), + /*location*/ parameter + ) + ) + ]) + ); + + setEmitFlags(forStatement, EmitFlags.CustomPrologue); + startOnNewLine(forStatement); + statements.push(forStatement); + } + + + + export function convertForOf(node: ForOfStatement, convertedLoopBodyStatements: Statement[], visitor: (node: Node) => VisitResult, enableSubstitutionsForBlockScopedBindings: () => void, diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 76ea6b2ddd0b8..121ea5e12340b 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -861,7 +861,7 @@ namespace ts { } if (constructor) { - addDefaultValueAssignmentsIfNeeded(statements, constructor); + addDefaultValueAssignmentsIfNeeded(statements, constructor, visitor, /*convertObjectRest*/ false); addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper); Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!"); @@ -954,7 +954,7 @@ namespace ts { // If this isn't a derived class, just capture 'this' for arrow functions if necessary. if (!hasExtendsClause) { if (ctor) { - addCaptureThisForNodeIfNeeded(statements, ctor); + addCaptureThisForNodeIfNeeded(statements, ctor, enableSubstitutionsForCapturedThis); } return SuperCaptureResult.NoReplacement; } @@ -1016,7 +1016,7 @@ namespace ts { } // Perform the capture. - captureThisForNode(statements, ctor, superCallExpression, firstStatement); + captureThisForNode(statements, ctor, superCallExpression, enableSubstitutionsForCapturedThis, firstStatement); // If we're actually replacing the original statement, we need to signal this to the caller. if (superCallExpression) { @@ -1085,242 +1085,6 @@ namespace ts { } } - /** - * Gets a value indicating whether we need to add default value assignments for a - * function-like node. - * - * @param node A function-like node. - */ - function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { - return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0; - } - - /** - * Adds statements to the body of a function-like node if it contains parameters with - * binding patterns or initializers. - * - * @param statements The statements for the new function body. - * @param node A function-like node. - */ - function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void { - if (!shouldAddDefaultValueAssignments(node)) { - return; - } - - for (const parameter of node.parameters) { - const { name, initializer, dotDotDotToken } = parameter; - - // A rest parameter cannot have a binding pattern or an initializer, - // so let's just ignore it. - if (dotDotDotToken) { - continue; - } - - if (isBindingPattern(name)) { - addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer); - } - else if (initializer) { - addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer); - } - } - } - - /** - * Adds statements to the body of a function-like node for parameters with binding patterns - * - * @param statements The statements for the new function body. - * @param parameter The parameter for the function. - * @param name The name of the parameter. - * @param initializer The initializer for the parameter. - */ - function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression): void { - const temp = getGeneratedNameForNode(parameter); - - // In cases where a binding pattern is simply '[]' or '{}', - // we usually don't want to emit a var declaration; however, in the presence - // of an initializer, we must emit that expression to preserve side effects. - if (name.elements.length > 0) { - statements.push( - setEmitFlags( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList( - flattenParameterDestructuring(parameter, temp, visitor) - ) - ), - EmitFlags.CustomPrologue - ) - ); - } - else if (initializer) { - statements.push( - setEmitFlags( - createStatement( - createAssignment( - temp, - visitNode(initializer, visitor, isExpression) - ) - ), - EmitFlags.CustomPrologue - ) - ); - } - } - - /** - * Adds statements to the body of a function-like node for parameters with initializers. - * - * @param statements The statements for the new function body. - * @param parameter The parameter for the function. - * @param name The name of the parameter. - * @param initializer The initializer for the parameter. - */ - function addDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { - initializer = visitNode(initializer, visitor, isExpression); - const statement = createIf( - createStrictEquality( - getSynthesizedClone(name), - createVoidZero() - ), - setEmitFlags( - createBlock([ - createStatement( - createAssignment( - setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap), - setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)), - /*location*/ parameter - ) - ) - ], /*location*/ parameter), - EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps - ), - /*elseStatement*/ undefined, - /*location*/ parameter - ); - statement.startsOnNewLine = true; - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue); - statements.push(statement); - } - - /** - * Gets a value indicating whether we need to add statements to handle a rest parameter. - * - * @param node A ParameterDeclaration node. - * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is - * part of a constructor declaration with a - * synthesized call to `super` - */ - function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) { - return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper; - } - - /** - * Adds statements to the body of a function-like node if it contains a rest parameter. - * - * @param statements The statements for the new function body. - * @param node A function-like node. - * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is - * part of a constructor declaration with a - * synthesized call to `super` - */ - function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void { - const parameter = lastOrUndefined(node.parameters); - if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { - return; - } - - // `declarationName` is the name of the local declaration for the parameter. - const declarationName = getMutableClone(parameter.name); - setEmitFlags(declarationName, EmitFlags.NoSourceMap); - - // `expressionName` is the name of the parameter used in expressions. - const expressionName = getSynthesizedClone(parameter.name); - const restIndex = node.parameters.length - 1; - const temp = createLoopVariable(); - - // var param = []; - statements.push( - setEmitFlags( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList([ - createVariableDeclaration( - declarationName, - /*type*/ undefined, - createArrayLiteral([]) - ) - ]), - /*location*/ parameter - ), - EmitFlags.CustomPrologue - ) - ); - - // for (var _i = restIndex; _i < arguments.length; _i++) { - // param[_i - restIndex] = arguments[_i]; - // } - const forStatement = createFor( - createVariableDeclarationList([ - createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) - ], /*location*/ parameter), - createLessThan( - temp, - createPropertyAccess(createIdentifier("arguments"), "length"), - /*location*/ parameter - ), - createPostfixIncrement(temp, /*location*/ parameter), - createBlock([ - startOnNewLine( - createStatement( - createAssignment( - createElementAccess( - expressionName, - createSubtract(temp, createLiteral(restIndex)) - ), - createElementAccess(createIdentifier("arguments"), temp) - ), - /*location*/ parameter - ) - ) - ]) - ); - - setEmitFlags(forStatement, EmitFlags.CustomPrologue); - startOnNewLine(forStatement); - statements.push(forStatement); - } - - /** - * Adds a statement to capture the `this` of a function declaration if it is needed. - * - * @param statements The statements for the new function body. - * @param node A node. - */ - function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): void { - if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { - captureThisForNode(statements, node, createThis()); - } - } - - function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, originalStatement?: Statement): void { - enableSubstitutionsForCapturedThis(); - const captureThisStatement = createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList([ - createVariableDeclaration( - "_this", - /*type*/ undefined, - initializer - ) - ]), - originalStatement - ); - - setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); - setSourceMapRange(captureThisStatement, node); - statements.push(captureThisStatement); - } - /** * Adds statements to the class body function for a class to define the members of the * class. @@ -1518,7 +1282,7 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - transformFunctionBody(node), + transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis), /*location*/ node ), /*original*/ node); @@ -1545,7 +1309,7 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - saveStateAndInvoke(node, transformFunctionBody), + saveStateAndInvoke(node, node => transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis)), location ), /*original*/ node @@ -1555,96 +1319,6 @@ namespace ts { return expression; } - /** - * Transforms the body of a function-like node. - * - * @param node A function-like node. - */ - function transformFunctionBody(node: FunctionLikeDeclaration) { - let multiLine = false; // indicates whether the block *must* be emitted as multiple lines - let singleLine = false; // indicates whether the block *may* be emitted as a single line - let statementsLocation: TextRange; - let closeBraceLocation: TextRange; - - const statements: Statement[] = []; - const body = node.body; - let statementOffset: number; - - startLexicalEnvironment(); - if (isBlock(body)) { - // ensureUseStrict is false because no new prologue-directive should be added. - // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array - statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); - } - - addCaptureThisForNodeIfNeeded(statements, node); - addDefaultValueAssignmentsIfNeeded(statements, node); - addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); - - // If we added any generated statements, this must be a multi-line block. - if (!multiLine && statements.length > 0) { - multiLine = true; - } - - if (isBlock(body)) { - statementsLocation = body.statements; - addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); - - // If the original body was a multi-line block, this must be a multi-line block. - if (!multiLine && body.multiLine) { - multiLine = true; - } - } - else { - Debug.assert(node.kind === SyntaxKind.ArrowFunction); - - // To align with the old emitter, we use a synthetic end position on the location - // for the statement list we synthesize when we down-level an arrow function with - // an expression function body. This prevents both comments and source maps from - // being emitted for the end position only. - statementsLocation = moveRangeEnd(body, -1); - - const equalsGreaterThanToken = (node).equalsGreaterThanToken; - if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) { - if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) { - singleLine = true; - } - else { - multiLine = true; - } - } - - const expression = visitNode(body, visitor, isExpression); - const returnStatement = createReturn(expression, /*location*/ body); - setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); - statements.push(returnStatement); - - // To align with the source map emit for the old emitter, we set a custom - // source map location for the close brace. - closeBraceLocation = body; - } - - const lexicalEnvironment = endLexicalEnvironment(); - addRange(statements, lexicalEnvironment); - - // If we added any final generated statements, this must be a multi-line block - if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { - multiLine = true; - } - - const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); - if (!multiLine && singleLine) { - setEmitFlags(block, EmitFlags.SingleLine); - } - - if (closeBraceLocation) { - setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation); - } - - setOriginalNode(block, node.body); - return block; - } - /** * Visits an ExpressionStatement that contains a destructuring assignment. * @@ -2912,7 +2586,7 @@ namespace ts { const statements: Statement[] = []; startLexicalEnvironment(); addRange(statements, prologue); - addCaptureThisForNodeIfNeeded(statements, node); + addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis); addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement)); addRange(statements, endLexicalEnvironment()); const clone = getMutableClone(node); diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 26864a123ea33..d57c86d06001b 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -5,8 +5,6 @@ namespace ts { export function transformESNext(context: TransformationContext) { const { - startLexicalEnvironment, - endLexicalEnvironment, hoistVariableDeclaration, } = context; let currentSourceFile: SourceFile; @@ -210,6 +208,11 @@ namespace ts { } function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { + const hasRest = forEach(node.parameters, isObjectRestParameter); + const body = hasRest ? + transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : + visitEachChild(node.body, visitor, context); + return setOriginalNode( createFunctionDeclaration( /*decorators*/ undefined, @@ -219,13 +222,17 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - transformFunctionBody(node) as Block, + body, /*location*/ node ), /*original*/ node); } function visitArrowFunction(node: ArrowFunction) { + const hasRest = forEach(node.parameters, isObjectRestParameter); + const body = hasRest ? + transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : + visitEachChild(node.body, visitor, context); const func = setOriginalNode( createArrowFunction( /*modifiers*/ undefined, @@ -233,7 +240,7 @@ namespace ts { visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, node.equalsGreaterThanToken, - transformFunctionBody(node), + body, /*location*/ node ), /*original*/ node @@ -243,6 +250,10 @@ namespace ts { } function visitFunctionExpression(node: FunctionExpression): Expression { + const hasRest = forEach(node.parameters, isObjectRestParameter); + const body = hasRest ? + transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : + visitEachChild(node.body, visitor, context); return setOriginalNode( createFunctionExpression( /*modifiers*/ undefined, @@ -251,173 +262,11 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - transformFunctionBody(node) as Block, + body, /*location*/ node ), /*original*/ node ); } - - /** - * Transforms the body of a function-like node. - * - * @param node A function-like node. - */ - function transformFunctionBody(node: FunctionLikeDeclaration): Block | Expression { - const hasRest = forEach(node.parameters, isObjectRestParameter); - if (!hasRest) { - return visitEachChild(node.body, visitor, context); - } - - let multiLine = false; // indicates whether the block *must* be emitted as multiple lines - let singleLine = false; // indicates whether the block *may* be emitted as a single line - let statementsLocation: TextRange; - let closeBraceLocation: TextRange; - - const statements: Statement[] = []; - const body = node.body; - let statementOffset: number; - - startLexicalEnvironment(); - if (isBlock(body)) { - // ensureUseStrict is false because no new prologue-directive should be added. - // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array - statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); - } - - addDefaultValueAssignmentsIfNeeded(statements, node); - - // If we added any generated statements, this must be a multi-line block. - if (!multiLine && statements.length > 0) { - multiLine = true; - } - - if (isBlock(body)) { - statementsLocation = body.statements; - addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); - - // If the original body was a multi-line block, this must be a multi-line block. - if (!multiLine && body.multiLine) { - multiLine = true; - } - } - else { - Debug.assert(node.kind === SyntaxKind.ArrowFunction); - - // To align with the old emitter, we use a synthetic end position on the location - // for the statement list we synthesize when we down-level an arrow function with - // an expression function body. This prevents both comments and source maps from - // being emitted for the end position only. - statementsLocation = moveRangeEnd(body, -1); - - const equalsGreaterThanToken = (node).equalsGreaterThanToken; - if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) { - if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) { - singleLine = true; - } - else { - multiLine = true; - } - } - - const expression = visitNode(body, visitor, isExpression); - const returnStatement = createReturn(expression, /*location*/ body); - setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); - statements.push(returnStatement); - - // To align with the source map emit for the old emitter, we set a custom - // source map location for the close brace. - closeBraceLocation = body; - } - - const lexicalEnvironment = endLexicalEnvironment(); - addRange(statements, lexicalEnvironment); - - // If we added any final generated statements, this must be a multi-line block - if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) { - multiLine = true; - } - - const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine); - if (!multiLine && singleLine) { - setEmitFlags(block, EmitFlags.SingleLine); - } - - if (closeBraceLocation) { - setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation); - } - - setOriginalNode(block, node.body); - return block; - } - - function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { - return !!(node.transformFlags & TransformFlags.ContainsDefaultValueAssignments); - } - - /** - * Adds statements to the body of a function-like node if it contains parameters with - * binding patterns or initializers. - * - * @param statements The statements for the new function body. - * @param node A function-like node. - */ - function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void { - if (!shouldAddDefaultValueAssignments(node)) { - return; - } - - for (const parameter of node.parameters) { - // A rest parameter cannot have a binding pattern or an initializer, - // so let's just ignore it. - if (parameter.dotDotDotToken) { - continue; - } - - if (isBindingPattern(parameter.name)) { - addDefaultValueAssignmentForBindingPattern(statements, parameter); - } - } - } - - /** - * Adds statements to the body of a function-like node for parameters with binding patterns - * - * @param statements The statements for the new function body. - * @param parameter The parameter for the function. - */ - function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration): void { - const temp = getGeneratedNameForNode(parameter); - - // In cases where a binding pattern is simply '[]' or '{}', - // we usually don't want to emit a var declaration; however, in the presence - // of an initializer, we must emit that expression to preserve side effects. - if ((parameter.name as BindingPattern).elements.length > 0) { - statements.push( - setEmitFlags( - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList( - flattenParameterDestructuring(parameter, temp, visitor, /*transformRest*/ true) - ) - ), - EmitFlags.CustomPrologue - ) - ); - } - else if (parameter.initializer) { - statements.push( - setEmitFlags( - createStatement( - createAssignment( - temp, - visitNode(parameter.initializer, visitor, isExpression) - ) - ), - EmitFlags.CustomPrologue - ) - ); - } - } } } From a55ed26d2be4ac49e6a0b4060eac6ea4ff2333b9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 4 Nov 2016 16:06:33 -0700 Subject: [PATCH 72/85] Spread any types to any --- src/compiler/checker.ts | 9 +- tests/baselines/reference/objectSpread.js | 7 + .../baselines/reference/objectSpread.symbols | 129 +++++++++--------- tests/baselines/reference/objectSpread.types | 9 ++ .../objectSpreadNegativeParse.errors.txt | 11 +- .../conformance/types/spread/objectSpread.ts | 4 + 6 files changed, 95 insertions(+), 74 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3475a9d52c6f7..20e90f4db2546 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5884,8 +5884,11 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol): ResolvedType { - Debug.assert(!!(left.flags & TypeFlags.Object) && !!(right.flags & TypeFlags.Object), "Only object types may be spread."); + function getSpreadType(left: Type, right: Type, symbol: Symbol): ResolvedType | IntrinsicType { + Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread."); + if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { + return anyType; + } const members = createMap(); const skippedPrivateMembers = createMap(); let stringIndexInfo: IndexInfo; @@ -10934,7 +10937,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadElementExpression).expression); - if (!(type.flags & TypeFlags.Object)) { + if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } diff --git a/tests/baselines/reference/objectSpread.js b/tests/baselines/reference/objectSpread.js index c19ead478cbd8..d1de48c5cabb2 100644 --- a/tests/baselines/reference/objectSpread.js +++ b/tests/baselines/reference/objectSpread.js @@ -38,6 +38,10 @@ getter.a = 12; // functions result in { } let spreadFunc = { ...(function () { }) }; +// any results in any +let anything: any; +let spreadAny = { ...anything }; + // methods are not enumerable class C { p = 1; m() { } } let c: C = new C() @@ -109,6 +113,9 @@ var getter = __assign({}, op, { c: 7 }); getter.a = 12; // functions result in { } var spreadFunc = __assign({}, (function () { })); +// any results in any +var anything; +var spreadAny = __assign({}, anything); // methods are not enumerable var C = (function () { function C() { diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index b95f8273724c2..4b0a62a5a24ec 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -154,123 +154,130 @@ getter.a = 12; let spreadFunc = { ...(function () { }) }; >spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3)) +// any results in any +let anything: any; +>anything : Symbol(anything, Decl(objectSpread.ts, 40, 3)) + +let spreadAny = { ...anything }; +>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 41, 3)) + // methods are not enumerable class C { p = 1; m() { } } ->C : Symbol(C, Decl(objectSpread.ts, 37, 42)) ->p : Symbol(C.p, Decl(objectSpread.ts, 40, 9)) ->m : Symbol(C.m, Decl(objectSpread.ts, 40, 16)) +>C : Symbol(C, Decl(objectSpread.ts, 41, 32)) +>p : Symbol(C.p, Decl(objectSpread.ts, 44, 9)) +>m : Symbol(C.m, Decl(objectSpread.ts, 44, 16)) let c: C = new C() ->c : Symbol(c, Decl(objectSpread.ts, 41, 3)) ->C : Symbol(C, Decl(objectSpread.ts, 37, 42)) ->C : Symbol(C, Decl(objectSpread.ts, 37, 42)) +>c : Symbol(c, Decl(objectSpread.ts, 45, 3)) +>C : Symbol(C, Decl(objectSpread.ts, 41, 32)) +>C : Symbol(C, Decl(objectSpread.ts, 41, 32)) let spreadC: { p: number } = { ...c } ->spreadC : Symbol(spreadC, Decl(objectSpread.ts, 42, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 42, 14)) +>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 46, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 46, 14)) // own methods are enumerable let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } }; ->cplus : Symbol(cplus, Decl(objectSpread.ts, 45, 3)) ->p : Symbol(p, Decl(objectSpread.ts, 45, 12)) ->plus : Symbol(plus, Decl(objectSpread.ts, 45, 23)) ->plus : Symbol(plus, Decl(objectSpread.ts, 45, 48)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3)) +>p : Symbol(p, Decl(objectSpread.ts, 49, 12)) +>plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) +>plus : Symbol(plus, Decl(objectSpread.ts, 49, 48)) cplus.plus(); ->cplus.plus : Symbol(plus, Decl(objectSpread.ts, 45, 23)) ->cplus : Symbol(cplus, Decl(objectSpread.ts, 45, 3)) ->plus : Symbol(plus, Decl(objectSpread.ts, 45, 23)) +>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) +>cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3)) +>plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) // new field's type conflicting with existing field is OK let changeTypeAfter: { a: string, b: string } = ->changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 49, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 49, 22)) ->b : Symbol(b, Decl(objectSpread.ts, 49, 33)) +>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 53, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 53, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 53, 33)) { ...o, a: 'wrong type?' } ->a : Symbol(a, Decl(objectSpread.ts, 50, 11)) +>a : Symbol(a, Decl(objectSpread.ts, 54, 11)) let changeTypeBefore: { a: number, b: string } = ->changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 51, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 51, 23)) ->b : Symbol(b, Decl(objectSpread.ts, 51, 34)) +>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 55, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 55, 23)) +>b : Symbol(b, Decl(objectSpread.ts, 55, 34)) { a: 'wrong type?', ...o }; ->a : Symbol(a, Decl(objectSpread.ts, 52, 5)) +>a : Symbol(a, Decl(objectSpread.ts, 56, 5)) let changeTypeBoth: { a: string, b: number } = ->changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 53, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 53, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 53, 32)) +>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 57, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 57, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 57, 32)) { ...o, ...swap }; // optional let definiteBoolean: { sn: boolean }; ->definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 57, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 57, 22)) +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 61, 22)) let definiteString: { sn: string }; ->definiteString : Symbol(definiteString, Decl(objectSpread.ts, 58, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 58, 21)) +>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 62, 21)) let optionalString: { sn?: string }; ->optionalString : Symbol(optionalString, Decl(objectSpread.ts, 59, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 59, 21)) +>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 63, 21)) let optionalNumber: { sn?: number }; ->optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 60, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 60, 21)) +>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 64, 21)) let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; ->optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 61, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 61, 25)) +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 65, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 65, 25)) let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; ->optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 62, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 62, 30)) +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 66, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 66, 30)) let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; ->allOptional : Symbol(allOptional, Decl(objectSpread.ts, 63, 3)) ->sn : Symbol(sn, Decl(objectSpread.ts, 63, 18)) +>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 67, 3)) +>sn : Symbol(sn, Decl(objectSpread.ts, 67, 18)) // computed property let computedFirst: { a: number, b: string, "before everything": number } = ->computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 66, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 66, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 66, 31)) +>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 70, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 70, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 70, 31)) { ['before everything']: 12, ...o, b: 'yes' } ->'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 67, 5)) ->b : Symbol(b, Decl(objectSpread.ts, 67, 38)) +>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 71, 5)) +>b : Symbol(b, Decl(objectSpread.ts, 71, 38)) let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } = ->computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 68, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 68, 21)) ->b : Symbol(b, Decl(objectSpread.ts, 68, 32)) ->c : Symbol(c, Decl(objectSpread.ts, 68, 43)) +>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 72, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 72, 21)) +>b : Symbol(b, Decl(objectSpread.ts, 72, 32)) +>c : Symbol(c, Decl(objectSpread.ts, 72, 43)) { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 69, 11)) ->b : Symbol(b, Decl(objectSpread.ts, 69, 34)) +>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 73, 11)) +>b : Symbol(b, Decl(objectSpread.ts, 73, 34)) let computedAfter: { a: number, b: string, "at the end": number } = ->computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 70, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 70, 20)) ->b : Symbol(b, Decl(objectSpread.ts, 70, 31)) +>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 74, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 74, 20)) +>b : Symbol(b, Decl(objectSpread.ts, 74, 31)) { ...o, b: 'yeah', ['at the end']: 14 } ->b : Symbol(b, Decl(objectSpread.ts, 71, 11)) ->'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 71, 22)) +>b : Symbol(b, Decl(objectSpread.ts, 75, 11)) +>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 75, 22)) // shortcut syntax let a = 12; ->a : Symbol(a, Decl(objectSpread.ts, 73, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 77, 3)) let shortCutted: { a: number, b: string } = { ...o, a } ->shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 74, 3)) ->a : Symbol(a, Decl(objectSpread.ts, 74, 18)) ->b : Symbol(b, Decl(objectSpread.ts, 74, 29)) ->a : Symbol(a, Decl(objectSpread.ts, 74, 51)) +>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 78, 3)) +>a : Symbol(a, Decl(objectSpread.ts, 78, 18)) +>b : Symbol(b, Decl(objectSpread.ts, 78, 29)) +>a : Symbol(a, Decl(objectSpread.ts, 78, 51)) diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index e9b9a6421c297..a1c70720d1296 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -230,6 +230,15 @@ let spreadFunc = { ...(function () { }) }; >(function () { }) : () => void >function () { } : () => void +// any results in any +let anything: any; +>anything : any + +let spreadAny = { ...anything }; +>spreadAny : any +>{ ...anything } : any +>anything : any + // methods are not enumerable class C { p = 1; m() { } } >C : C diff --git a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt index 987172ef867bf..b37200c4f0293 100644 --- a/tests/baselines/reference/objectSpreadNegativeParse.errors.txt +++ b/tests/baselines/reference/objectSpreadNegativeParse.errors.txt @@ -1,22 +1,17 @@ -tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,15): error TS2304: Cannot find name 'o'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,18): error TS1109: Expression expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,15): error TS1109: Expression expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,16): error TS2304: Cannot find name 'o'. -tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,12): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,15): error TS2304: Cannot find name 'matchMedia'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,28): error TS1005: ',' expected. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,31): error TS1128: Declaration or statement expected. -tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,13): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,16): error TS2304: Cannot find name 'get'. tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error TS1005: ',' expected. -==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (13 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (10 errors) ==== let o7 = { ...o? }; - ~~~~~ -!!! error TS2698: Spread types may only be created from object types. ~ !!! error TS2304: Cannot find name 'o'. ~ @@ -29,8 +24,6 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error T ~ !!! error TS2304: Cannot find name 'o'. let o9 = { ...matchMedia() { }}; - ~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. ~~~~~~~~~~ !!! error TS2304: Cannot find name 'matchMedia'. ~ @@ -38,8 +31,6 @@ tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error T ~ !!! error TS1128: Declaration or statement expected. let o10 = { ...get x() { return 12; }}; - ~~~~~~ -!!! error TS2698: Spread types may only be created from object types. ~~~ !!! error TS2304: Cannot find name 'get'. ~ diff --git a/tests/cases/conformance/types/spread/objectSpread.ts b/tests/cases/conformance/types/spread/objectSpread.ts index 3336196e136c3..ebf2bdb2adede 100644 --- a/tests/cases/conformance/types/spread/objectSpread.ts +++ b/tests/cases/conformance/types/spread/objectSpread.ts @@ -38,6 +38,10 @@ getter.a = 12; // functions result in { } let spreadFunc = { ...(function () { }) }; +// any results in any +let anything: any; +let spreadAny = { ...anything }; + // methods are not enumerable class C { p = 1; m() { } } let c: C = new C() From a84c7aeea4f0109af303dfad05232011abfca212 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 08:36:03 -0800 Subject: [PATCH 73/85] Rename SpreadElementExpression -> SpreadAssignment and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement --- src/compiler/binder.ts | 14 +++++----- src/compiler/checker.ts | 30 +++++++++++----------- src/compiler/emitter.ts | 6 ++--- src/compiler/factory.ts | 4 +-- src/compiler/parser.ts | 16 ++++++------ src/compiler/transformers/destructuring.ts | 4 +-- src/compiler/transformers/es2015.ts | 6 ++--- src/compiler/transformers/esnext.ts | 4 +-- src/compiler/types.ts | 16 +++++------- src/compiler/utilities.ts | 14 +++++----- src/compiler/visitor.ts | 10 ++++---- src/services/breakpoints.ts | 2 +- src/services/utilities.ts | 4 +-- 13 files changed, 64 insertions(+), 66 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b0c456a677068..902d20b0cfd3a 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1138,8 +1138,8 @@ namespace ts { } else if (node.kind === SyntaxKind.ArrayLiteralExpression) { for (const e of (node).elements) { - if (e.kind === SyntaxKind.SpreadExpression) { - bindAssignmentTargetFlow((e).expression); + if (e.kind === SyntaxKind.SpreadElement) { + bindAssignmentTargetFlow((e).expression); } else { bindDestructuringTargetFlow(e); @@ -1154,8 +1154,8 @@ namespace ts { else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { bindAssignmentTargetFlow((p).name); } - else if (p.kind === SyntaxKind.SpreadElementExpression) { - bindAssignmentTargetFlow((p).expression); + else if (p.kind === SyntaxKind.SpreadAssignment) { + bindAssignmentTargetFlow((p).expression); } } } @@ -1929,7 +1929,7 @@ namespace ts { case SyntaxKind.EnumMember: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes); - case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SpreadAssignment: case SyntaxKind.JsxSpreadAttribute: emitFlags |= NodeFlags.HasSpreadAttribute; return; @@ -3127,8 +3127,8 @@ namespace ts { } break; - case SyntaxKind.SpreadExpression: - case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SpreadElement: + case SyntaxKind.SpreadAssignment: // This node is ES6 or ES future syntax, but is handled by a containing node. transformFlags |= TransformFlags.ContainsSpreadExpression; break; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 20e90f4db2546..09172d02ad7e7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8640,7 +8640,7 @@ namespace ts { return getTypeOfDestructuredArrayElement(getAssignedType(node), indexOf(node.elements, element)); } - function getAssignedTypeOfSpreadExpression(node: SpreadExpression): Type { + function getAssignedTypeOfSpreadExpression(node: SpreadElement): Type { return getTypeOfDestructuredSpreadExpression(getAssignedType(node.parent)); } @@ -8665,8 +8665,8 @@ namespace ts { return undefinedType; case SyntaxKind.ArrayLiteralExpression: return getAssignedTypeOfArrayLiteralElement(parent, node); - case SyntaxKind.SpreadExpression: - return getAssignedTypeOfSpreadExpression(parent); + case SyntaxKind.SpreadElement: + return getAssignedTypeOfSpreadExpression(parent); case SyntaxKind.PropertyAssignment: return getAssignedTypeOfPropertyAssignment(parent); case SyntaxKind.ShorthandPropertyAssignment: @@ -10697,7 +10697,7 @@ namespace ts { return mapper && mapper.context; } - function checkSpreadExpression(node: SpreadExpression, contextualMapper?: TypeMapper): Type { + function checkSpreadExpression(node: SpreadElement, contextualMapper?: TypeMapper): Type { // It is usually not safe to call checkExpressionCached if we can be contextually typing. // You can tell that we are contextually typing because of the contextualMapper parameter. // While it is true that a spread element can have a contextual type, it does not do anything @@ -10719,7 +10719,7 @@ namespace ts { const elementTypes: Type[] = []; const inDestructuringPattern = isAssignmentTarget(node); for (const e of elements) { - if (inDestructuringPattern && e.kind === SyntaxKind.SpreadExpression) { + if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) { // Given the following situation: // var c: {}; // [...c] = ["", 0]; @@ -10732,7 +10732,7 @@ namespace ts { // get the contextual element type from it. So we do something similar to // getContextualTypeForElementExpression, which will crucially not error // if there is no index type / iterated type. - const restArrayType = checkExpression((e).expression, contextualMapper); + const restArrayType = checkExpression((e).expression, contextualMapper); const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) || (languageVersion >= ScriptTarget.ES2015 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined); if (restElementType) { @@ -10743,7 +10743,7 @@ namespace ts { const type = checkExpressionForMutableLocation(e, contextualMapper); elementTypes.push(type); } - hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadExpression; + hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement; } if (!hasSpreadElement) { // If array literal is actually a destructuring pattern, mark it as an implied type. We do this such @@ -10927,7 +10927,7 @@ namespace ts { prop.target = member; member = prop; } - else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { + else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (propertiesArray.length > 0) { spread = getSpreadType(spread, createObjectLiteralType(), node.symbol); propertiesArray = []; @@ -10936,7 +10936,7 @@ namespace ts { hasComputedNumberProperty = false; typeFlags = 0; } - const type = checkExpression((memberDecl as SpreadElementExpression).expression); + const type = checkExpression((memberDecl as SpreadAssignment).expression); if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; @@ -11905,7 +11905,7 @@ namespace ts { function getSpreadArgumentIndex(args: Expression[]): number { for (let i = 0; i < args.length; i++) { const arg = args[i]; - if (arg && arg.kind === SyntaxKind.SpreadExpression) { + if (arg && arg.kind === SyntaxKind.SpreadElement) { return i; } } @@ -13893,7 +13893,7 @@ namespace ts { const elements = node.elements; const element = elements[elementIndex]; if (element.kind !== SyntaxKind.OmittedExpression) { - if (element.kind !== SyntaxKind.SpreadExpression) { + if (element.kind !== SyntaxKind.SpreadElement) { const propName = "" + elementIndex; const type = isTypeAny(sourceType) ? sourceType @@ -13920,7 +13920,7 @@ namespace ts { error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); } else { - const restExpression = (element).expression; + const restExpression = (element).expression; if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression).operatorToken.kind === SyntaxKind.EqualsToken) { error((restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); } @@ -14553,8 +14553,8 @@ namespace ts { return checkBinaryExpression(node, contextualMapper); case SyntaxKind.ConditionalExpression: return checkConditionalExpression(node, contextualMapper); - case SyntaxKind.SpreadExpression: - return checkSpreadExpression(node, contextualMapper); + case SyntaxKind.SpreadElement: + return checkSpreadExpression(node, contextualMapper); case SyntaxKind.OmittedExpression: return undefinedWideningType; case SyntaxKind.YieldExpression: @@ -20511,7 +20511,7 @@ namespace ts { const GetOrSetAccessor = GetAccessor | SetAccessor; for (const prop of node.properties) { - if (prop.kind === SyntaxKind.SpreadElementExpression) { + if (prop.kind === SyntaxKind.SpreadAssignment) { continue; } const name = prop.name; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0ee598c507aed..6d4688ac004b4 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -822,8 +822,8 @@ const _super = (function (geti, seti) { return emitTemplateExpression(node); case SyntaxKind.YieldExpression: return emitYieldExpression(node); - case SyntaxKind.SpreadExpression: - return emitSpreadExpression(node); + case SyntaxKind.SpreadElement: + return emitSpreadExpression(node); case SyntaxKind.ClassExpression: return emitClassExpression(node); case SyntaxKind.OmittedExpression: @@ -1374,7 +1374,7 @@ const _super = (function (geti, seti) { emitExpressionWithPrefix(" ", node.expression); } - function emitSpreadExpression(node: SpreadExpression) { + function emitSpreadExpression(node: SpreadElement) { write("..."); emitExpression(node.expression); } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index c7fe7d7057499..536ee4cb4b4bf 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -692,12 +692,12 @@ namespace ts { } export function createSpread(expression: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.SpreadExpression, location); + const node = createNode(SyntaxKind.SpreadElement, location); node.expression = parenthesizeExpressionForList(expression); return node; } - export function updateSpread(node: SpreadExpression, expression: Expression) { + export function updateSpread(node: SpreadElement, expression: Expression) { if (node.expression !== expression) { return updateNode(createSpread(expression, node), node); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 464f6ca01d802..9e0a5b4cd3379 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -74,8 +74,8 @@ namespace ts { visitNode(cbNode, (node).questionToken) || visitNode(cbNode, (node).equalsToken) || visitNode(cbNode, (node).objectAssignmentInitializer); - case SyntaxKind.SpreadElementExpression: - return visitNode(cbNode, (node).expression); + case SyntaxKind.SpreadAssignment: + return visitNode(cbNode, (node).expression); case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -199,8 +199,8 @@ namespace ts { visitNode(cbNode, (node).whenTrue) || visitNode(cbNode, (node).colonToken) || visitNode(cbNode, (node).whenFalse); - case SyntaxKind.SpreadExpression: - return visitNode(cbNode, (node).expression); + case SyntaxKind.SpreadElement: + return visitNode(cbNode, (node).expression); case SyntaxKind.Block: case SyntaxKind.ModuleBlock: return visitNodes(cbNodes, (node).statements); @@ -4123,15 +4123,15 @@ namespace ts { return finishNode(node); } - function parseSpreadExpression(): Expression { - const node = createNode(SyntaxKind.SpreadExpression); + function parseSpreadElement(): Expression { + const node = createNode(SyntaxKind.SpreadElement); parseExpected(SyntaxKind.DotDotDotToken); node.expression = parseAssignmentExpressionOrHigher(); return finishNode(node); } function parseArgumentOrArrayLiteralElement(): Expression { - return token() === SyntaxKind.DotDotDotToken ? parseSpreadExpression() : + return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : token() === SyntaxKind.CommaToken ? createNode(SyntaxKind.OmittedExpression) : parseAssignmentExpressionOrHigher(); } @@ -4166,7 +4166,7 @@ namespace ts { const fullStart = scanner.getStartPos(); const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); if (dotDotDotToken) { - const spreadElement = createNode(SyntaxKind.SpreadElementExpression, fullStart); + const spreadElement = createNode(SyntaxKind.SpreadAssignment, fullStart); spreadElement.expression = parseAssignmentExpressionOrHigher(); return addJSDocComment(finishNode(spreadElement)); } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 89beade577d80..8994a28a97ed0 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -308,11 +308,11 @@ namespace ts { const e = elements[i]; if (e.kind !== SyntaxKind.OmittedExpression) { // Assignment for target = value.propName should highligh whole property, hence use e as source map node - if (e.kind !== SyntaxKind.SpreadExpression) { + if (e.kind !== SyntaxKind.SpreadElement) { emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e); } else if (i === numElements - 1) { - emitDestructuringAssignment((e).expression, createArraySlice(value, i), e); + emitDestructuringAssignment((e).expression, createArraySlice(value, i), e); } } } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index e262b413b4c72..6869b2b5eb727 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -2890,7 +2890,7 @@ namespace ts { * * @param node A SpreadExpression node. */ - function visitExpressionOfSpread(node: SpreadExpression) { + function visitExpressionOfSpread(node: SpreadElement) { return visitNode(node.expression, visitor, isExpression); } @@ -3266,11 +3266,11 @@ namespace ts { } const callArgument = singleOrUndefined((statementExpression).arguments); - if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadExpression) { + if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElement) { return false; } - const expression = (callArgument).expression; + const expression = (callArgument).expression; return isIdentifier(expression) && expression === parameter.name; } } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1a8ed7da5eb4a..38ff99fd78a7e 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -36,12 +36,12 @@ namespace ts { let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[]; const objects: Expression[] = []; for (const e of elements) { - if (e.kind === SyntaxKind.SpreadElementExpression) { + if (e.kind === SyntaxKind.SpreadAssignment) { if (chunkObject) { objects.push(createObjectLiteral(chunkObject)); chunkObject = undefined; } - const target = (e as SpreadElementExpression).expression; + const target = (e as SpreadAssignment).expression; objects.push(visitNode(target, visitor, isExpression)); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d3b4cb3b6e7df..3f40272bd4cc4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -246,7 +246,7 @@ namespace ts { ConditionalExpression, TemplateExpression, YieldExpression, - SpreadExpression, + SpreadElement, ClassExpression, OmittedExpression, ExpressionWithTypeArguments, @@ -320,7 +320,7 @@ namespace ts { // Property assignments PropertyAssignment, ShorthandPropertyAssignment, - SpreadElementExpression, + SpreadAssignment, // Enum EnumMember, @@ -662,7 +662,6 @@ namespace ts { initializer?: Expression; // Optional initializer } - // @kind(SyntaxKind.PropertyDeclaration) export interface PropertyDeclaration extends ClassElement { kind: SyntaxKind.PropertyDeclaration; questionToken?: QuestionToken; // Present for use with reporting a grammar error @@ -676,7 +675,7 @@ namespace ts { name?: PropertyName; } - export type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | MethodDeclaration | AccessorDeclaration | SpreadElementExpression; + export type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | MethodDeclaration | AccessorDeclaration | SpreadAssignment; export interface PropertyAssignment extends ObjectLiteralElement { kind: SyntaxKind.PropertyAssignment; @@ -695,8 +694,8 @@ namespace ts { objectAssignmentInitializer?: Expression; } - export interface SpreadElementExpression extends ObjectLiteralElement { - kind: SyntaxKind.SpreadElementExpression; + export interface SpreadAssignment extends ObjectLiteralElement { + kind: SyntaxKind.SpreadAssignment; expression: Expression; } @@ -1285,9 +1284,8 @@ namespace ts { multiLine?: boolean; } - // @kind(SyntaxKind.SpreadExpression) - export interface SpreadExpression extends Expression { - kind: SyntaxKind.SpreadExpression; + export interface SpreadElement extends Expression { + kind: SyntaxKind.SpreadElement; expression: Expression; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cd3e6ab9575b5..b668fe6eb1582 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1179,7 +1179,7 @@ namespace ts { case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.BinaryExpression: case SyntaxKind.ConditionalExpression: - case SyntaxKind.SpreadExpression: + case SyntaxKind.SpreadElement: case SyntaxKind.TemplateExpression: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.OmittedExpression: @@ -1641,7 +1641,7 @@ namespace ts { return (parent).initializer === node ? AssignmentKind.Definite : AssignmentKind.None; case SyntaxKind.ParenthesizedExpression: case SyntaxKind.ArrayLiteralExpression: - case SyntaxKind.SpreadExpression: + case SyntaxKind.SpreadElement: node = parent; break; case SyntaxKind.ShorthandPropertyAssignment: @@ -2226,7 +2226,7 @@ namespace ts { case SyntaxKind.YieldExpression: return 2; - case SyntaxKind.SpreadExpression: + case SyntaxKind.SpreadElement: return 1; default: @@ -3862,7 +3862,7 @@ namespace ts { const kind = node.kind; return kind === SyntaxKind.PropertyAssignment || kind === SyntaxKind.ShorthandPropertyAssignment - || kind === SyntaxKind.SpreadElementExpression + || kind === SyntaxKind.SpreadAssignment || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor @@ -3950,8 +3950,8 @@ namespace ts { || kind === SyntaxKind.NoSubstitutionTemplateLiteral; } - export function isSpreadExpression(node: Node): node is SpreadExpression { - return node.kind === SyntaxKind.SpreadExpression; + export function isSpreadExpression(node: Node): node is SpreadElement { + return node.kind === SyntaxKind.SpreadElement; } export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments { @@ -4009,7 +4009,7 @@ namespace ts { || kind === SyntaxKind.YieldExpression || kind === SyntaxKind.ArrowFunction || kind === SyntaxKind.BinaryExpression - || kind === SyntaxKind.SpreadExpression + || kind === SyntaxKind.SpreadElement || kind === SyntaxKind.AsExpression || kind === SyntaxKind.OmittedExpression || isUnaryExpressionKind(kind); diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 4bcc697a99911..0fb0b182345e6 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -267,9 +267,9 @@ namespace ts { case SyntaxKind.VoidExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.YieldExpression: - case SyntaxKind.SpreadExpression: + case SyntaxKind.SpreadElement: case SyntaxKind.NonNullExpression: - result = reduceNode((node).expression, f, result); + result = reduceNode((node).expression, f, result); break; case SyntaxKind.PrefixUnaryExpression: @@ -870,9 +870,9 @@ namespace ts { return updateYield(node, visitNode((node).expression, visitor, isExpression)); - case SyntaxKind.SpreadExpression: - return updateSpread(node, - visitNode((node).expression, visitor, isExpression)); + case SyntaxKind.SpreadElement: + return updateSpread(node, + visitNode((node).expression, visitor, isExpression)); case SyntaxKind.ClassExpression: return updateClassExpression(node, diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index f1cc233e67680..6825ccb6371ff 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -264,7 +264,7 @@ namespace ts.BreakpointResolver { // a or ...c or d: x from // [a, b, ...c] or { a, b } or { d: x } from destructuring pattern if ((node.kind === SyntaxKind.Identifier || - node.kind == SyntaxKind.SpreadExpression || + node.kind == SyntaxKind.SpreadElement || node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 2db495a51f9e8..cfb6aae010b63 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -530,8 +530,8 @@ namespace ts { case SyntaxKind.DeleteExpression: case SyntaxKind.VoidExpression: case SyntaxKind.YieldExpression: - case SyntaxKind.SpreadExpression: - const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadExpression); + case SyntaxKind.SpreadElement: + const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement); return isCompletedNode(unaryWordExpression.expression, sourceFile); case SyntaxKind.TaggedTemplateExpression: From 6a82ae4cbb209d6f3fdad74cdf6146747ed33449 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 09:04:00 -0800 Subject: [PATCH 74/85] Add SpreadAssignment to visitors 1. visitNode 2. reduceNode 3. emit This fixes an emit bug for setters. --- src/compiler/emitter.ts | 9 +++++++++ src/compiler/factory.ts | 17 +++++++++++++++-- src/compiler/visitor.ts | 10 +++++++++- .../baselines/reference/objectSpreadNegative.js | 2 +- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6d4688ac004b4..b0413b2578e8f 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -732,6 +732,8 @@ const _super = (function (geti, seti) { return emitPropertyAssignment(node); case SyntaxKind.ShorthandPropertyAssignment: return emitShorthandPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitSpreadAssignment(node as SpreadAssignment); // Enum case SyntaxKind.EnumMember: @@ -2102,6 +2104,13 @@ const _super = (function (geti, seti) { } } + function emitSpreadAssignment(node: SpreadAssignment) { + if (node.expression) { + write("..."); + emitExpression(node.expression); + } + } + // // Enum // diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 536ee4cb4b4bf..fd2b7c1ccee34 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1399,14 +1399,27 @@ namespace ts { return node; } - export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) { + export function createSpreadAssignment(expression: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.SpreadAssignment, location); + node.expression = expression !== undefined ? parenthesizeExpressionForList(expression) : undefined; + return node; + } + + export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) { if (node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer) { return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer, node), node); } return node; } - // Top-level nodes + export function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) { + if (node.expression !== expression) { + return updateNode(createSpreadAssignment(expression, node), node); + } + return node; + } + + // Top-level nodes export function updateSourceFileNode(node: SourceFile, statements: Statement[]) { if (node.statements !== statements) { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 0fb0b182345e6..db59c30934507 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -510,6 +510,10 @@ namespace ts { result = reduceNode((node).objectAssignmentInitializer, f, result); break; + case SyntaxKind.SpreadAssignment: + result = reduceNode((node as SpreadAssignment).expression, f, result); + break; + // Top-level nodes case SyntaxKind.SourceFile: result = reduceLeft((node).statements, f, result); @@ -1125,7 +1129,11 @@ namespace ts { visitNode((node).name, visitor, isIdentifier), visitNode((node).objectAssignmentInitializer, visitor, isExpression)); - // Top-level nodes + case SyntaxKind.SpreadAssignment: + return updateSpreadAssignment(node as SpreadAssignment, + visitNode((node as SpreadAssignment).expression, visitor, isExpression)); + + // Top-level nodes case SyntaxKind.SourceFile: context.startLexicalEnvironment(); return updateSourceFileNode(node, diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 4faacd9744450..6287f4559a79b 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -123,7 +123,7 @@ spreadStr.charAt(1); // error, no methods either var spreadFunc = __assign({}, function () { }); spreadFunc(); // error, no call signature // write-only properties get skipped -var setterOnly = __assign({ set b(bad: number) { } }); +var setterOnly = __assign({ set b(bad) { } }); setterOnly.b = 12; // error, 'b' does not exist // methods are skipped because they aren't enumerable var C = (function () { From 7b9a42f9958b072f057d42d506b7e082ebf19974 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 09:54:48 -0800 Subject: [PATCH 75/85] Add --target esnext Currently, this disables the rest and spread transforms. This will change as proposals enter and leave stage 3. --- src/compiler/commandLineParser.ts | 1 + src/compiler/emitter.ts | 7 +++++-- src/compiler/transformer.ts | 5 ++++- src/compiler/types.ts | 3 ++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 50399fd5c38e7..6e5256bafa4df 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -265,6 +265,7 @@ namespace ts { "es2015": ScriptTarget.ES2015, "es2016": ScriptTarget.ES2016, "es2017": ScriptTarget.ES2017, + "esnext": ScriptTarget.ESNext, }), description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015, paramType: Diagnostics.VERSION, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index b0413b2578e8f..ce37492f66662 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -732,7 +732,7 @@ const _super = (function (geti, seti) { return emitPropertyAssignment(node); case SyntaxKind.ShorthandPropertyAssignment: return emitShorthandPropertyAssignment(node); - case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.SpreadAssignment: return emitSpreadAssignment(node as SpreadAssignment); // Enum @@ -2214,7 +2214,10 @@ const _super = (function (geti, seti) { helpersEmitted = true; } - if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasSpreadAttribute)) { + if ((languageVersion < ScriptTarget.ESNext || currentSourceFile.scriptKind === ScriptKind.JSX || currentSourceFile.scriptKind === ScriptKind.TSX) && + compilerOptions.jsx !== JsxEmit.Preserve && + !assignEmitted && + node.flags & NodeFlags.HasSpreadAttribute) { writeLines(assignHelper); assignEmitted = true; } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 069b1e46af56b..b005b1906f696 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -117,7 +117,10 @@ namespace ts { transformers.push(transformJsx); } - transformers.push(transformESNext); + if (languageVersion < ScriptTarget.ESNext) { + transformers.push(transformESNext); + } + if (languageVersion < ScriptTarget.ES2017) { transformers.push(transformES2017); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3f40272bd4cc4..13b66c1c0aa64 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3171,7 +3171,8 @@ namespace ts { ES2015 = 2, ES2016 = 3, ES2017 = 4, - Latest = ES2017, + ESNext = 5, + Latest = ESNext, } export const enum LanguageVariant { From d4a5b0855caf74542903963fc012e75ca7ef3a48 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 09:56:48 -0800 Subject: [PATCH 76/85] Add --target esnext tests and update baselines --- src/harness/unittests/commandLineParsing.ts | 2 +- .../unittests/convertCompilerOptionsFromJson.ts | 2 +- .../reference/objectSpreadNoTransform.js | 8 ++++++++ .../reference/objectSpreadNoTransform.symbols | 10 ++++++++++ .../reference/objectSpreadNoTransform.types | 16 ++++++++++++++++ .../types/spread/objectSpreadNoTransform.ts | 3 +++ 6 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/objectSpreadNoTransform.js create mode 100644 tests/baselines/reference/objectSpreadNoTransform.symbols create mode 100644 tests/baselines/reference/objectSpreadNoTransform.types create mode 100644 tests/cases/conformance/types/spread/objectSpreadNoTransform.ts diff --git a/src/harness/unittests/commandLineParsing.ts b/src/harness/unittests/commandLineParsing.ts index c15490738fa87..890f167e2dd2c 100644 --- a/src/harness/unittests/commandLineParsing.ts +++ b/src/harness/unittests/commandLineParsing.ts @@ -165,7 +165,7 @@ namespace ts { start: undefined, length: undefined, }, { - messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017'", + messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'esnext'", category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code, diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index 2942675f0ac5e..23c372b531330 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -176,7 +176,7 @@ namespace ts { file: undefined, start: 0, length: 0, - messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017'", + messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'esnext'", code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category }] diff --git a/tests/baselines/reference/objectSpreadNoTransform.js b/tests/baselines/reference/objectSpreadNoTransform.js new file mode 100644 index 0000000000000..8916c621969ed --- /dev/null +++ b/tests/baselines/reference/objectSpreadNoTransform.js @@ -0,0 +1,8 @@ +//// [objectSpreadNoTransform.ts] +const y = { a: 'yes', b: 'no' }; +const o = { x: 1, ...y }; + + +//// [objectSpreadNoTransform.js] +const y = { a: 'yes', b: 'no' }; +const o = { x: 1, ...y }; diff --git a/tests/baselines/reference/objectSpreadNoTransform.symbols b/tests/baselines/reference/objectSpreadNoTransform.symbols new file mode 100644 index 0000000000000..4d77bc848303d --- /dev/null +++ b/tests/baselines/reference/objectSpreadNoTransform.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/types/spread/objectSpreadNoTransform.ts === +const y = { a: 'yes', b: 'no' }; +>y : Symbol(y, Decl(objectSpreadNoTransform.ts, 0, 5)) +>a : Symbol(a, Decl(objectSpreadNoTransform.ts, 0, 11)) +>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 0, 21)) + +const o = { x: 1, ...y }; +>o : Symbol(o, Decl(objectSpreadNoTransform.ts, 1, 5)) +>x : Symbol(x, Decl(objectSpreadNoTransform.ts, 1, 11)) + diff --git a/tests/baselines/reference/objectSpreadNoTransform.types b/tests/baselines/reference/objectSpreadNoTransform.types new file mode 100644 index 0000000000000..3a412e2894eea --- /dev/null +++ b/tests/baselines/reference/objectSpreadNoTransform.types @@ -0,0 +1,16 @@ +=== tests/cases/conformance/types/spread/objectSpreadNoTransform.ts === +const y = { a: 'yes', b: 'no' }; +>y : { a: string; b: string; } +>{ a: 'yes', b: 'no' } : { a: string; b: string; } +>a : string +>'yes' : "yes" +>b : string +>'no' : "no" + +const o = { x: 1, ...y }; +>o : { a: string; b: string; x: number; } +>{ x: 1, ...y } : { a: string; b: string; x: number; } +>x : number +>1 : 1 +>y : any + diff --git a/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts b/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts new file mode 100644 index 0000000000000..00039117a20ef --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts @@ -0,0 +1,3 @@ +// @target: esnext +const y = { a: 'yes', b: 'no' }; +const o = { x: 1, ...y }; From 83e95d43f8db0f19d810399d80c85228c612acf3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 10:58:31 -0800 Subject: [PATCH 77/85] Revert unneeded change and comments per PR --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 09172d02ad7e7..7612bf1dddf19 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4597,7 +4597,7 @@ namespace ts { result.valueDeclaration = declarations[0]; } result.isReadonly = isReadonly; - result.type = containingType.flags & TypeFlags.Intersection ? getIntersectionType(propTypes) : getUnionType(propTypes); + result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes); return result; } @@ -5880,7 +5880,7 @@ namespace ts { } /** - * Since the source of spread types are object literals and type literals, which are not binary, + * Since the source of spread types are object literals, which are not binary, * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ From 9977936190fd15c1ec4043276ba1f7a8815b3d06 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 11:34:37 -0800 Subject: [PATCH 78/85] Do not emit __rest for --target esnext --- src/compiler/emitter.ts | 2 +- .../baselines/reference/objectSpreadNoTransform.js | 6 ++++++ .../reference/objectSpreadNoTransform.symbols | 10 ++++++++++ .../reference/objectSpreadNoTransform.types | 14 ++++++++++++++ .../types/spread/objectSpreadNoTransform.ts | 3 +++ 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f22f695a3e588..fa0d44a695f54 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2231,7 +2231,7 @@ const _super = (function (geti, seti) { assignEmitted = true; } - if (!restEmitted && node.flags & NodeFlags.HasRestAttribute) { + if (languageVersion < ScriptTarget.ESNext && !restEmitted && node.flags & NodeFlags.HasRestAttribute) { writeLines(restHelper); restEmitted = true; } diff --git a/tests/baselines/reference/objectSpreadNoTransform.js b/tests/baselines/reference/objectSpreadNoTransform.js index 8916c621969ed..3442d0864092d 100644 --- a/tests/baselines/reference/objectSpreadNoTransform.js +++ b/tests/baselines/reference/objectSpreadNoTransform.js @@ -1,8 +1,14 @@ //// [objectSpreadNoTransform.ts] const y = { a: 'yes', b: 'no' }; const o = { x: 1, ...y }; +var b; +var rest; +({ b, ...rest } = o); //// [objectSpreadNoTransform.js] const y = { a: 'yes', b: 'no' }; const o = { x: 1, ...y }; +var b; +var rest; +({ b, ...rest } = o); diff --git a/tests/baselines/reference/objectSpreadNoTransform.symbols b/tests/baselines/reference/objectSpreadNoTransform.symbols index 4d77bc848303d..d7dac11a53041 100644 --- a/tests/baselines/reference/objectSpreadNoTransform.symbols +++ b/tests/baselines/reference/objectSpreadNoTransform.symbols @@ -8,3 +8,13 @@ const o = { x: 1, ...y }; >o : Symbol(o, Decl(objectSpreadNoTransform.ts, 1, 5)) >x : Symbol(x, Decl(objectSpreadNoTransform.ts, 1, 11)) +var b; +>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 2, 3)) + +var rest; +>rest : Symbol(rest, Decl(objectSpreadNoTransform.ts, 3, 3)) + +({ b, ...rest } = o); +>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 4, 2)) +>o : Symbol(o, Decl(objectSpreadNoTransform.ts, 1, 5)) + diff --git a/tests/baselines/reference/objectSpreadNoTransform.types b/tests/baselines/reference/objectSpreadNoTransform.types index 3a412e2894eea..0a6c867e8fed4 100644 --- a/tests/baselines/reference/objectSpreadNoTransform.types +++ b/tests/baselines/reference/objectSpreadNoTransform.types @@ -14,3 +14,17 @@ const o = { x: 1, ...y }; >1 : 1 >y : any +var b; +>b : any + +var rest; +>rest : any + +({ b, ...rest } = o); +>({ b, ...rest } = o) : { a: string; b: string; x: number; } +>{ b, ...rest } = o : { a: string; b: string; x: number; } +>{ b, ...rest } : any +>b : any +>rest : any +>o : { a: string; b: string; x: number; } + diff --git a/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts b/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts index 00039117a20ef..36c75e70887bb 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNoTransform.ts @@ -1,3 +1,6 @@ // @target: esnext const y = { a: 'yes', b: 'no' }; const o = { x: 1, ...y }; +var b; +var rest; +({ b, ...rest } = o); From 567f5636e3e4c9bf4790f99fd8bb2e07afcb8561 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 13:02:05 -0800 Subject: [PATCH 79/85] Create spread property types eagerly This avoids the need for a synthetic symbol and later code called from getTypeOfSymbol. --- src/compiler/checker.ts | 44 +++++++++++++-------------------------- src/compiler/types.ts | 1 - src/compiler/utilities.ts | 1 + 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b3200ab239bfe..73e4e273d66b0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3550,9 +3550,6 @@ namespace ts { if (symbol.flags & SymbolFlags.Instantiated) { return getTypeOfInstantiatedSymbol(symbol); } - if (symbol.flags & SymbolFlags.SyntheticProperty && symbol.syntheticKind === SyntheticSymbolKind.Spread) { - return getTypeOfSpreadProperty(symbol); - } if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { return getTypeOfVariableOrParameterOrProperty(symbol); } @@ -3571,14 +3568,6 @@ namespace ts { return unknownType; } - function getTypeOfSpreadProperty(symbol: Symbol) { - const links = getSymbolLinks(symbol); - if (!links.type) { - links.type = getUnionType([getTypeOfSymbol(links.leftSpread), getTypeOfSymbol(links.rightSpread)]); - } - return links.type; - } - function getTargetType(type: Type): Type { return getObjectFlags(type) & ObjectFlags.Reference ? (type).target : type; } @@ -4588,7 +4577,6 @@ namespace ts { propTypes.push(type); } const result = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | commonFlags, name); - result.syntheticKind = SyntheticSymbolKind.UnionOrIntersection; result.containingType = containingType; result.hasNonUniformType = hasNonUniformType; result.isPartial = isPartial; @@ -5932,9 +5920,9 @@ namespace ts { const rightProp = members[leftProp.name]; if (rightProp.flags & SymbolFlags.Optional) { const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations); - const flags = SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty | (leftProp.flags & SymbolFlags.Optional); + const flags = SymbolFlags.Property | SymbolFlags.Transient | (leftProp.flags & SymbolFlags.Optional); const result = createSymbol(flags, leftProp.name); - result.syntheticKind = SyntheticSymbolKind.Spread; + result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeOfSymbol(rightProp)]); result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; @@ -19220,23 +19208,21 @@ namespace ts { function getRootSymbols(symbol: Symbol): Symbol[] { if (symbol.flags & SymbolFlags.SyntheticProperty) { - if (symbol.syntheticKind === SyntheticSymbolKind.Spread) { - const links = getSymbolLinks(symbol); - return [links.leftSpread, links.rightSpread]; - } - else { - const symbols: Symbol[] = []; - const name = symbol.name; - forEach(getSymbolLinks(symbol).containingType.types, t => { - const symbol = getPropertyOfType(t, name); - if (symbol) { - symbols.push(symbol); - } - }); - return symbols; - } + const symbols: Symbol[] = []; + const name = symbol.name; + forEach(getSymbolLinks(symbol).containingType.types, t => { + const symbol = getPropertyOfType(t, name); + if (symbol) { + symbols.push(symbol); + } + }); + return symbols; } else if (symbol.flags & SymbolFlags.Transient) { + if ((symbol as SymbolLinks).leftSpread) { + const links = symbol as SymbolLinks; + return [links.leftSpread, links.rightSpread]; + } let target: Symbol; let next = symbol; while (next = getSymbolLinks(next).target) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index dcff28d6a4887..61bbff691bc05 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2590,7 +2590,6 @@ namespace ts { /* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments - /* @internal */ syntheticKind?: SyntheticSymbolKind; // Synthetic symbols are either spread or union/intersection } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b668fe6eb1582..53a4ad33f3400 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4311,6 +4311,7 @@ namespace ts { namespace ts { export function getDefaultLibFileName(options: CompilerOptions): string { switch (options.target) { + case ScriptTarget.ESNext: case ScriptTarget.ES2017: return "lib.es2017.d.ts"; case ScriptTarget.ES2016: From bd5ce284c9c2d8b29d131100615db437dde5ae28 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 13:35:36 -0800 Subject: [PATCH 80/85] Set spread type symbols in checkObjectLiteral Instead of getSpreadType. Also clean up special-case handling inside getSpreadType to be more readable. --- src/compiler/checker.ts | 19 ++++++++++--------- .../baselines/reference/objectSpread.symbols | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 73e4e273d66b0..263ee47a6b702 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5881,7 +5881,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol): ResolvedType | IntrinsicType { + function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): ResolvedType | IntrinsicType { Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread."); if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; @@ -5900,14 +5900,14 @@ namespace ts { numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); } - const isFromSpread = right.symbol !== symbol; for (const rightProp of getPropertiesOfType(right)) { + // we approximate own properties as non-methods plus methods that are inside the object literal + const isOwnProperty = !(rightProp.flags & SymbolFlags.Method) || isFromObjectLiteral; + const isSetterWithoutGetter = rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor); if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { skippedPrivateMembers[rightProp.name] = true; } - else if (!(rightProp.flags & SymbolFlags.Method && isFromSpread) && - !(rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor))) { - // skip methods from spreads and accessors with setters but no getters + else if (isOwnProperty && !isSetterWithoutGetter) { members[rightProp.name] = rightProp; } } @@ -5937,7 +5937,7 @@ namespace ts { members[leftProp.name] = leftProp; } } - return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } function createLiteralType(flags: TypeFlags, text: string) { @@ -10947,7 +10947,7 @@ namespace ts { } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol); + spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true); propertiesArray = []; propertiesTable = createMap(); hasComputedStringProperty = false; @@ -10959,7 +10959,7 @@ namespace ts { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - spread = getSpreadType(spread, type, node.symbol); + spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false); continue; } else { @@ -11003,9 +11003,10 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol); + spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true); } spread.flags |= propagatedFlags; + spread.symbol = node.symbol; return spread; } diff --git a/tests/baselines/reference/objectSpread.symbols b/tests/baselines/reference/objectSpread.symbols index 4b0a62a5a24ec..9946b313f52f3 100644 --- a/tests/baselines/reference/objectSpread.symbols +++ b/tests/baselines/reference/objectSpread.symbols @@ -182,6 +182,7 @@ let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } } >p : Symbol(p, Decl(objectSpread.ts, 49, 12)) >plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) >plus : Symbol(plus, Decl(objectSpread.ts, 49, 48)) +>this : Symbol(__object, Decl(objectSpread.ts, 41, 15)) cplus.plus(); >cplus.plus : Symbol(plus, Decl(objectSpread.ts, 49, 23)) From e1c50e1c406a27a505f4c8393a81f2b1232d51ae Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 7 Nov 2016 13:57:26 -0800 Subject: [PATCH 81/85] Address more PR comments --- src/compiler/checker.ts | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 263ee47a6b702..8ac6b0f647190 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4488,10 +4488,9 @@ namespace ts { function getPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); - if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertiesOfUnionOrIntersectionType(type); - } - return getPropertiesOfObjectType(type); + return type.flags & TypeFlags.UnionOrIntersection ? + getPropertiesOfUnionOrIntersectionType(type) : + getPropertiesOfObjectType(type); } /** @@ -4581,9 +4580,6 @@ namespace ts { result.hasNonUniformType = hasNonUniformType; result.isPartial = isPartial; result.declarations = declarations; - if (declarations.length) { - result.valueDeclaration = declarations[0]; - } result.isReadonly = isReadonly; result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes); return result; @@ -5057,7 +5053,7 @@ namespace ts { const declaration = getIndexDeclarationOfSymbol(symbol, kind); if (declaration) { return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, - (getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration); + (getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration); } return undefined; } @@ -5926,9 +5922,6 @@ namespace ts { result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; - if (declarations.length) { - result.valueDeclaration = declarations[0]; - } result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp); members[leftProp.name] = result; } @@ -15196,11 +15189,9 @@ namespace ts { forEach(node.members, checkSourceElement); if (produceDiagnostics) { const type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); - if (type.flags & TypeFlags.Object) { - checkIndexConstraints(type); - checkTypeForDuplicateIndexSignatures(node); - checkObjectTypeForDuplicateDeclarations(node); - } + checkIndexConstraints(type); + checkTypeForDuplicateIndexSignatures(node); + checkObjectTypeForDuplicateDeclarations(node); } } @@ -17259,7 +17250,7 @@ namespace ts { // perform property check if property or indexer is declared in 'type' // this allows to rule out cases when both property and indexer are inherited from the base class let errorNode: Node; - if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { + if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) { errorNode = prop.valueDeclaration; } else if (indexDeclaration) { @@ -20538,7 +20529,7 @@ namespace ts { continue; } const name = prop.name; - if (name && name.kind === SyntaxKind.ComputedPropertyName) { + if (name.kind === SyntaxKind.ComputedPropertyName) { // If the name is not a ComputedPropertyName, the grammar checking will skip it checkGrammarComputedPropertyName(name); } From 214ce38a6a64441232b5e7e72d78a2687edfe743 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 9 Nov 2016 10:47:54 -0800 Subject: [PATCH 82/85] Downlevel array destructuring to ES6 in object rest Previously array destructuring inside an object destructuring with an object rest would downlevel the array destructuring to ES5. This breaks if the code that targets ES2015 is using iterators instead of arrays since iterators don't support [0] or .slice that the ES5 emit uses. --- src/compiler/factory.ts | 3 +- src/compiler/transformers/destructuring.ts | 141 ++++++++++++++++----- 2 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 790f9c2df6fb8..40f5910009ca8 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3568,8 +3568,7 @@ namespace ts { setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps); let forStatement: ForStatement | ForOfStatement; - if(convertObjectRest) { - + if (convertObjectRest) { forStatement = createForOf( createVariableDeclarationList([ createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression) diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 66b907d4d9030..bba09710898f0 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -52,7 +52,7 @@ namespace ts { location = value; } - flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, emitRestAssignment, transformRest, visitor); + flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); if (needsValue) { expressions.push(value); @@ -98,7 +98,7 @@ namespace ts { transformRest?: boolean) { const declarations: VariableDeclaration[] = []; - flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, emitRestAssignment, transformRest, visitor); + flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor); return declarations; @@ -140,7 +140,7 @@ namespace ts { const declarations: VariableDeclaration[] = []; let pendingAssignments: Expression[]; - flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, emitRestAssignment, transformRest, visitor); + flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor); return declarations; @@ -201,7 +201,7 @@ namespace ts { const pendingAssignments: Expression[] = []; - flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, emitRestAssignment, /*transformRest*/ false, visitor); + flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor); const expression = inlineExpressions(pendingAssignments); aggregateTransformFlags(expression); @@ -244,6 +244,7 @@ namespace ts { location: TextRange, emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void, emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier, + recordTempVariable: (node: Identifier) => void, emitRestAssignment: (elements: (ObjectLiteralElementLike[] | BindingElement[]), value: Expression, location: TextRange, original: Node) => void, transformRest: boolean, visitor?: (node: Node) => VisitResult) { @@ -307,48 +308,91 @@ namespace ts { value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); } - let es2015: ObjectLiteralElementLike[] = []; + let bindingElements: ObjectLiteralElementLike[] = []; for (let i = 0; i < properties.length; i++) { const p = properties[i]; if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - if (transformRest && !(p.transformFlags & TransformFlags.ContainsSpreadExpression)) { - es2015.push(p); - } - else { - if (es2015.length) { - emitRestAssignment(es2015, value, location, target); - es2015 = []; + if (!transformRest || + p.transformFlags & TransformFlags.ContainsSpreadExpression || + (p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression)) { + if (bindingElements.length) { + emitRestAssignment(bindingElements, value, location, target); + bindingElements = []; } const propName = (p).name; const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? p : (p).initializer || propName; // Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p); } + else { + bindingElements.push(p); + } } else if (i === properties.length - 1 && p.kind === SyntaxKind.SpreadAssignment) { Debug.assert((p as SpreadAssignment).expression.kind === SyntaxKind.Identifier); - if (es2015.length) { - emitRestAssignment(es2015, value, location, target); - es2015 = []; + if (bindingElements.length) { + emitRestAssignment(bindingElements, value, location, target); + bindingElements = []; } const propName = (p as SpreadAssignment).expression as Identifier; const restCall = createRestCall(value, target.properties, p => p.name, target); emitDestructuringAssignment(propName, restCall, p); } } - if (es2015.length) { - emitRestAssignment(es2015, value, location, target); - es2015 = []; + if (bindingElements.length) { + emitRestAssignment(bindingElements, value, location, target); + bindingElements = []; } } function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { + if (transformRest) { + emitESNextArrayLiteralAssignment(target, value, location); + } + else { + emitES2015ArrayLiteralAssignment(target, value, location); + } + } + + function emitESNextArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { const elements = target.elements; const numElements = elements.length; if (numElements !== 1) { // For anything but a single element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. - // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment + // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment + value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + } + + const expressions: Expression[] = []; + const spreadContainingExpressions: [Expression, Identifier][] = []; + for (let i = 0; i < numElements; i++) { + const e = elements[i]; + if (e.kind === SyntaxKind.OmittedExpression) { + continue; + } + if (e.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) { + const tmp = createTempVariable(recordTempVariable); + spreadContainingExpressions.push([e, tmp]); + expressions.push(tmp); + } + else { + expressions.push(e); + } + } + emitAssignment(updateArrayLiteral(target, expressions) as any as Identifier, value, undefined, undefined); + for (const [e, tmp] of spreadContainingExpressions) { + emitDestructuringAssignment(e, tmp, e); + } + } + + function emitES2015ArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { + const elements = target.elements; + const numElements = elements.length; + if (numElements !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); } @@ -413,7 +457,7 @@ namespace ts { value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment); } if (name.kind === SyntaxKind.ArrayBindingPattern) { - emitArrayBindingElement(name, value); + emitArrayBindingElement(name as ArrayBindingPattern, value); } else { emitObjectBindingElement(target, value); @@ -421,7 +465,16 @@ namespace ts { } } - function emitArrayBindingElement(name: BindingPattern, value: Expression) { + function emitArrayBindingElement(name: ArrayBindingPattern, value: Expression) { + if (transformRest) { + emitESNextArrayBindingElement(name, value); + } + else { + emitES2015ArrayBindingElement(name, value); + } + } + + function emitES2015ArrayBindingElement(name: ArrayBindingPattern, value: Expression) { const elements = name.elements; const numElements = elements.length; for (let i = 0; i < numElements; i++) { @@ -439,20 +492,44 @@ namespace ts { } } + function emitESNextArrayBindingElement(name: ArrayBindingPattern, value: Expression) { + const elements = name.elements; + const numElements = elements.length; + const bindingElements: BindingElement[] = []; + const spreadContainingElements: BindingElement[] = []; + for (let i = 0; i < numElements; i++) { + const element = elements[i]; + if (isOmittedExpression(element)) { + continue; + } + if (element.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) { + spreadContainingElements.push(element); + bindingElements.push(createBindingElement(undefined, undefined, getGeneratedNameForNode(element), undefined, value)); + } + else { + bindingElements.push(element); + } + } + emitAssignment(updateArrayBindingPattern(name, bindingElements) as any as Identifier, value, undefined, undefined); + for (const element of spreadContainingElements) { + emitBindingElement(element, getGeneratedNameForNode(element)); + } + } + function emitObjectBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) { const name = target.name as BindingPattern; const elements = name.elements; const numElements = elements.length; - let es2015: BindingElement[] = []; + let bindingElements: BindingElement[] = []; for (let i = 0; i < numElements; i++) { const element = elements[i]; if (isOmittedExpression(element)) { continue; } if (i === numElements - 1 && element.dotDotDotToken) { - if (es2015.length) { - emitRestAssignment(es2015, value, target, target); - es2015 = []; + if (bindingElements.length) { + emitRestAssignment(bindingElements, value, target, target); + bindingElements = []; } const restCall = createRestCall(value, name.elements, @@ -462,21 +539,21 @@ namespace ts { } else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) { // do not emit until we have a complete bundle of ES2015 syntax - es2015.push(element); + bindingElements.push(element); } else { - if (es2015.length) { - emitRestAssignment(es2015, value, target, target); - es2015 = []; + if (bindingElements.length) { + emitRestAssignment(bindingElements, value, target, target); + bindingElements = []; } // Rewrite element to a declaration with an initializer that fetches property const propName = element.propertyName || element.name; emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); } } - if (es2015.length) { - emitRestAssignment(es2015, value, target, target); - es2015 = []; + if (bindingElements.length) { + emitRestAssignment(bindingElements, value, target, target); + bindingElements = []; } } From 01969475cf576b4f476beeb5aca648e743eb5cd2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 9 Nov 2016 10:51:56 -0800 Subject: [PATCH 83/85] Improve nested destructuring test for ESNext emit Now with object destructuring inside array destructuring inside object destructuring! Each with their own array/object rest! Also updates baselines. --- .../reference/objectRestAssignment.js | 26 ++++++++---- .../reference/objectRestAssignment.symbols | 31 ++++++++++++++ .../reference/objectRestAssignment.types | 41 +++++++++++++++++++ .../types/rest/objectRestAssignment.ts | 8 ++++ 4 files changed, 99 insertions(+), 7 deletions(-) diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js index 20f87ff837564..41620d59b584f 100644 --- a/tests/baselines/reference/objectRestAssignment.js +++ b/tests/baselines/reference/objectRestAssignment.js @@ -5,6 +5,13 @@ let other: number; let rest: { }; let complex: { x: { ka, ki }, y: number }; ({x: { ka, ...nested }, y: other, ...rest} = complex); + +// should be: +let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string }; + +// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit; +({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit); //// [objectRestAssignment.js] @@ -14,10 +21,15 @@ var __rest = (this && this.__rest) || function (s, e) { t[p] = s[p]; return t; }; -var ka; -var nested; -var other; -var rest; -var complex; -(_a = complex.x, (ka = _a.ka, _a), nested = __rest(_a, ["ka"]), (other = complex.y, complex), rest = __rest(complex, ["x", "y"]), complex); -var _a; +let ka; +let nested; +let other; +let rest; +let complex; +(_a = complex.x, { ka } = _a, nested = __rest(_a, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]), complex); +// should be: +let overEmit; +// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +var _b = overEmit.a, [_c, ...y] = _b, nested2 = __rest(_c, []), _d = overEmit.b, { z } = _d, c = __rest(_d, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +(_e = overEmit.a, [_f, ...y] = _e, nested2 = __rest(_f, []), _g = overEmit.b, { z } = _g, c = __rest(_g, ["z"]), rest2 = __rest(overEmit, ["a", "b"]), overEmit); +var _a, _e, _f, _g; diff --git a/tests/baselines/reference/objectRestAssignment.symbols b/tests/baselines/reference/objectRestAssignment.symbols index 38127dbee2d2c..4cb27e6e7ecd6 100644 --- a/tests/baselines/reference/objectRestAssignment.symbols +++ b/tests/baselines/reference/objectRestAssignment.symbols @@ -26,3 +26,34 @@ let complex: { x: { ka, ki }, y: number }; >other : Symbol(other, Decl(objectRestAssignment.ts, 2, 3)) >complex : Symbol(complex, Decl(objectRestAssignment.ts, 4, 3)) +// should be: +let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string }; +>overEmit : Symbol(overEmit, Decl(objectRestAssignment.ts, 8, 3)) +>a : Symbol(a, Decl(objectRestAssignment.ts, 8, 15)) +>ka : Symbol(ka, Decl(objectRestAssignment.ts, 8, 20)) +>x : Symbol(x, Decl(objectRestAssignment.ts, 8, 32)) +>b : Symbol(b, Decl(objectRestAssignment.ts, 8, 47)) +>z : Symbol(z, Decl(objectRestAssignment.ts, 8, 52)) +>ki : Symbol(ki, Decl(objectRestAssignment.ts, 8, 63)) +>ku : Symbol(ku, Decl(objectRestAssignment.ts, 8, 75)) +>ke : Symbol(ke, Decl(objectRestAssignment.ts, 8, 89)) +>ko : Symbol(ko, Decl(objectRestAssignment.ts, 8, 101)) + +// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit; +>a : Symbol(a, Decl(objectRestAssignment.ts, 8, 15)) +>nested2 : Symbol(nested2, Decl(objectRestAssignment.ts, 11, 11)) +>y : Symbol(y, Decl(objectRestAssignment.ts, 11, 25)) +>b : Symbol(b, Decl(objectRestAssignment.ts, 8, 47)) +>z : Symbol(z, Decl(objectRestAssignment.ts, 11, 37)) +>c : Symbol(c, Decl(objectRestAssignment.ts, 11, 40)) +>rest2 : Symbol(rest2, Decl(objectRestAssignment.ts, 11, 48)) +>overEmit : Symbol(overEmit, Decl(objectRestAssignment.ts, 8, 3)) + +({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit); +>a : Symbol(a, Decl(objectRestAssignment.ts, 12, 2)) +>y : Symbol(y, Decl(objectRestAssignment.ts, 11, 25)) +>b : Symbol(b, Decl(objectRestAssignment.ts, 12, 29)) +>z : Symbol(z, Decl(objectRestAssignment.ts, 12, 34)) +>overEmit : Symbol(overEmit, Decl(objectRestAssignment.ts, 8, 3)) + diff --git a/tests/baselines/reference/objectRestAssignment.types b/tests/baselines/reference/objectRestAssignment.types index a4d88f89bb276..38aa00ce61dc4 100644 --- a/tests/baselines/reference/objectRestAssignment.types +++ b/tests/baselines/reference/objectRestAssignment.types @@ -32,3 +32,44 @@ let complex: { x: { ka, ki }, y: number }; >rest : any >complex : { x: { ka: any; ki: any; }; y: number; } +// should be: +let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string }; +>overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; } +>a : { ka: string; x: string; }[] +>ka : string +>x : string +>b : { z: string; ki: string; ku: string; } +>z : string +>ki : string +>ku : string +>ke : string +>ko : string + +// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit; +>a : any +>nested2 : { ka: string; x: string; } +>y : { ka: string; x: string; }[] +>b : any +>z : string +>c : { ki: string; ku: string; } +>rest2 : { ke: string; ko: string; } +>overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; } + +({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit); +>({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit) : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; } +>{ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; } +>{ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } : { ke: string; ko: string; a: { ka: string; x: string; }[]; b: { ki: string; ku: string; z: string; }; } +>a : { ka: string; x: string; }[] +>[{ ...nested2 }, ...y] : { ka: string; x: string; }[] +>{ ...nested2 } : { ka: string; x: string; } +>nested2 : any +>...y : { ka: string; x: string; } +>y : { ka: string; x: string; }[] +>b : { ki: string; ku: string; z: string; } +>{ z, ...c } : { ki: string; ku: string; z: string; } +>z : string +>c : any +>rest2 : any +>overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; } + diff --git a/tests/cases/conformance/types/rest/objectRestAssignment.ts b/tests/cases/conformance/types/rest/objectRestAssignment.ts index 4c8da304bc3c3..dedc99b1f713a 100644 --- a/tests/cases/conformance/types/rest/objectRestAssignment.ts +++ b/tests/cases/conformance/types/rest/objectRestAssignment.ts @@ -1,6 +1,14 @@ +// @target: es2015 let ka: any; let nested: { ki }; let other: number; let rest: { }; let complex: { x: { ka, ki }, y: number }; ({x: { ka, ...nested }, y: other, ...rest} = complex); + +// should be: +let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string }; + +// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]); +var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit; +({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit); From fcf32c444f8d4eb8382d9ff7b3fb3c278b8ec1b8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 9 Nov 2016 13:39:42 -0800 Subject: [PATCH 84/85] Treat `| undefined` like optionality in spread type --- src/compiler/checker.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8ac6b0f647190..8558871e6bf40 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4523,7 +4523,7 @@ namespace ts { t; } - function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string) { + function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol { const types = containingType.types; let props: Symbol[]; // Flags we want to propagate to the result if they exist in all source symbols @@ -5914,11 +5914,12 @@ namespace ts { } if (leftProp.name in members) { const rightProp = members[leftProp.name]; - if (rightProp.flags & SymbolFlags.Optional) { + const rightType = getTypeOfSymbol(rightProp); + if (maybeTypeOfKind(rightType, TypeFlags.Undefined) || rightProp.flags & SymbolFlags.Optional) { const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations); const flags = SymbolFlags.Property | SymbolFlags.Transient | (leftProp.flags & SymbolFlags.Optional); const result = createSymbol(flags, leftProp.name); - result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeOfSymbol(rightProp)]); + result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeWithFacts(rightType, TypeFacts.NEUndefined)]); result.leftSpread = leftProp; result.rightSpread = rightProp; result.declarations = declarations; From 9b1f43bdda5118046ce7b604ca978a83fc4e10f5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 9 Nov 2016 13:40:21 -0800 Subject: [PATCH 85/85] Add strictNullChecks test for object spread --- .../reference/objectSpreadStrictNull.js | 43 +++++++++ .../reference/objectSpreadStrictNull.symbols | 60 +++++++++++++ .../reference/objectSpreadStrictNull.types | 88 +++++++++++++++++++ .../types/spread/objectSpreadStrictNull.ts | 21 +++++ 4 files changed, 212 insertions(+) create mode 100644 tests/baselines/reference/objectSpreadStrictNull.js create mode 100644 tests/baselines/reference/objectSpreadStrictNull.symbols create mode 100644 tests/baselines/reference/objectSpreadStrictNull.types create mode 100644 tests/cases/conformance/types/spread/objectSpreadStrictNull.ts diff --git a/tests/baselines/reference/objectSpreadStrictNull.js b/tests/baselines/reference/objectSpreadStrictNull.js new file mode 100644 index 0000000000000..84604d728cdfc --- /dev/null +++ b/tests/baselines/reference/objectSpreadStrictNull.js @@ -0,0 +1,43 @@ +//// [objectSpreadStrictNull.ts] + +function f( + definiteBoolean: { sn: boolean }, + definiteString: { sn: string }, + optionalString: { sn?: string }, + optionalNumber: { sn?: number }, + undefinedString: { sn: string | undefined }, + undefinedNumber: { sn: number | undefined }) { + // optional + let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; + + // undefined + let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; + let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; + let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; + + let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; +} + + +//// [objectSpreadStrictNull.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +function f(definiteBoolean, definiteString, optionalString, optionalNumber, undefinedString, undefinedNumber) { + // optional + var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber); + var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber); + var allOptional = __assign({}, optionalString, optionalNumber); + // undefined + var undefinedUnionStops = __assign({}, definiteBoolean, definiteString, undefinedNumber); + var undefinedUnionDuplicates = __assign({}, definiteBoolean, definiteString, undefinedString, undefinedNumber); + var allUndefined = __assign({}, undefinedString, undefinedNumber); + var undefinedWithOptionalContinues = __assign({}, definiteBoolean, undefinedString, optionalNumber); +} diff --git a/tests/baselines/reference/objectSpreadStrictNull.symbols b/tests/baselines/reference/objectSpreadStrictNull.symbols new file mode 100644 index 0000000000000..85def473ce492 --- /dev/null +++ b/tests/baselines/reference/objectSpreadStrictNull.symbols @@ -0,0 +1,60 @@ +=== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts === + +function f( +>f : Symbol(f, Decl(objectSpreadStrictNull.ts, 0, 0)) + + definiteBoolean: { sn: boolean }, +>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 1, 11)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 2, 22)) + + definiteString: { sn: string }, +>definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 2, 37)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 3, 21)) + + optionalString: { sn?: string }, +>optionalString : Symbol(optionalString, Decl(objectSpreadStrictNull.ts, 3, 35)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 4, 21)) + + optionalNumber: { sn?: number }, +>optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 4, 36)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 5, 21)) + + undefinedString: { sn: string | undefined }, +>undefinedString : Symbol(undefinedString, Decl(objectSpreadStrictNull.ts, 5, 36)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 6, 22)) + + undefinedNumber: { sn: number | undefined }) { +>undefinedNumber : Symbol(undefinedNumber, Decl(objectSpreadStrictNull.ts, 6, 48)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 7, 22)) + + // optional + let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpreadStrictNull.ts, 9, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 9, 29)) + + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpreadStrictNull.ts, 10, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 10, 34)) + + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +>allOptional : Symbol(allOptional, Decl(objectSpreadStrictNull.ts, 11, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 11, 22)) + + // undefined + let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; +>undefinedUnionStops : Symbol(undefinedUnionStops, Decl(objectSpreadStrictNull.ts, 14, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 14, 30)) + + let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; +>undefinedUnionDuplicates : Symbol(undefinedUnionDuplicates, Decl(objectSpreadStrictNull.ts, 15, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 15, 35)) + + let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; +>allUndefined : Symbol(allUndefined, Decl(objectSpreadStrictNull.ts, 16, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 16, 23)) + + let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; +>undefinedWithOptionalContinues : Symbol(undefinedWithOptionalContinues, Decl(objectSpreadStrictNull.ts, 18, 7)) +>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 18, 41)) +} + diff --git a/tests/baselines/reference/objectSpreadStrictNull.types b/tests/baselines/reference/objectSpreadStrictNull.types new file mode 100644 index 0000000000000..a91295b2bca78 --- /dev/null +++ b/tests/baselines/reference/objectSpreadStrictNull.types @@ -0,0 +1,88 @@ +=== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts === + +function f( +>f : (definiteBoolean: { sn: boolean; }, definiteString: { sn: string; }, optionalString: { sn?: string | undefined; }, optionalNumber: { sn?: number | undefined; }, undefinedString: { sn: string | undefined; }, undefinedNumber: { sn: number | undefined; }) => void + + definiteBoolean: { sn: boolean }, +>definiteBoolean : { sn: boolean; } +>sn : boolean + + definiteString: { sn: string }, +>definiteString : { sn: string; } +>sn : string + + optionalString: { sn?: string }, +>optionalString : { sn?: string | undefined; } +>sn : string | undefined + + optionalNumber: { sn?: number }, +>optionalNumber : { sn?: number | undefined; } +>sn : number | undefined + + undefinedString: { sn: string | undefined }, +>undefinedString : { sn: string | undefined; } +>sn : string | undefined + + undefinedNumber: { sn: number | undefined }) { +>undefinedNumber : { sn: number | undefined; } +>sn : number | undefined + + // optional + let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; +>optionalUnionStops : { sn: string | number; } +>sn : string | number +>{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { sn: string | number; } +>definiteBoolean : any +>definiteString : any +>optionalNumber : any + + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; +>optionalUnionDuplicates : { sn: string | number; } +>sn : string | number +>{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { sn: string | number; } +>definiteBoolean : any +>definiteString : any +>optionalString : any +>optionalNumber : any + + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; +>allOptional : { sn?: string | number | undefined; } +>sn : string | number | undefined +>{ ...optionalString, ...optionalNumber } : { sn?: string | number | undefined; } +>optionalString : any +>optionalNumber : any + + // undefined + let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; +>undefinedUnionStops : { sn: string | number; } +>sn : string | number +>{ ...definiteBoolean, ...definiteString, ...undefinedNumber } : { sn: string | number; } +>definiteBoolean : any +>definiteString : any +>undefinedNumber : any + + let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; +>undefinedUnionDuplicates : { sn: string | number; } +>sn : string | number +>{ ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber } : { sn: string | number; } +>definiteBoolean : any +>definiteString : any +>undefinedString : any +>undefinedNumber : any + + let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; +>allUndefined : { sn: string | number | undefined; } +>sn : string | number | undefined +>{ ...undefinedString, ...undefinedNumber } : { sn: string | number | undefined; } +>undefinedString : any +>undefinedNumber : any + + let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; +>undefinedWithOptionalContinues : { sn: string | number | boolean; } +>sn : string | number | boolean +>{ ...definiteBoolean, ...undefinedString, ...optionalNumber } : { sn: string | number | boolean; } +>definiteBoolean : any +>undefinedString : any +>optionalNumber : any +} + diff --git a/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts b/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts new file mode 100644 index 0000000000000..087d47df26c35 --- /dev/null +++ b/tests/cases/conformance/types/spread/objectSpreadStrictNull.ts @@ -0,0 +1,21 @@ +// @strictNullChecks: true + +function f( + definiteBoolean: { sn: boolean }, + definiteString: { sn: string }, + optionalString: { sn?: string }, + optionalNumber: { sn?: number }, + undefinedString: { sn: string | undefined }, + undefinedNumber: { sn: number | undefined }) { + // optional + let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber }; + let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber }; + let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber }; + + // undefined + let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber }; + let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber }; + let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber }; + + let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber }; +}