From 18c692a429421d7231d8a58b784c452e40176d82 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 19 Oct 2016 13:14:06 -0700 Subject: [PATCH] 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 55d4361dc3e..8e196da87de 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,59 +8194,33 @@ 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); + 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 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) { const properties = getPropertiesOfObjectType(target); for (const targetProp of properties) {