Introduce sameMap function

This commit is contained in:
Anders Hejlsberg 2016-10-06 13:25:42 -07:00
parent b5c10553b5
commit 9c4190b1fb
2 changed files with 38 additions and 12 deletions

View File

@ -7404,7 +7404,7 @@ namespace ts {
type.flags & TypeFlags.NumberLiteral ? numberType :
type.flags & TypeFlags.BooleanLiteral ? booleanType :
type.flags & TypeFlags.EnumLiteral ? (<EnumLiteralType>type).baseType :
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(map((<UnionType>type).types, getBaseTypeOfLiteralType)) :
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((<UnionType>type).types, getBaseTypeOfLiteralType)) :
type;
}
@ -7413,7 +7413,7 @@ namespace ts {
type.flags & TypeFlags.NumberLiteral && type.flags & TypeFlags.FreshLiteral ? numberType :
type.flags & TypeFlags.BooleanLiteral ? booleanType :
type.flags & TypeFlags.EnumLiteral ? (<EnumLiteralType>type).baseType :
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(map((<UnionType>type).types, getWidenedLiteralType)) :
type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum) ? getUnionType(sameMap((<UnionType>type).types, getWidenedLiteralType)) :
type;
}
@ -7552,10 +7552,10 @@ namespace ts {
return getWidenedTypeOfObjectLiteral(type);
}
if (type.flags & TypeFlags.Union) {
return getUnionType(map((<UnionType>type).types, getWidenedConstituentType));
return getUnionType(sameMap((<UnionType>type).types, getWidenedConstituentType));
}
if (isArrayType(type) || isTupleType(type)) {
return createTypeReference((<TypeReference>type).target, map((<TypeReference>type).typeArguments, getWidenedType));
return createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
}
}
return type;
@ -7973,7 +7973,7 @@ namespace ts {
const widenLiteralTypes = context.inferences[index].topLevel &&
!hasPrimitiveConstraint(signature.typeParameters[index]) &&
(context.inferences[index].isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), signature.typeParameters[index]));
const baseInferences = widenLiteralTypes ? map(inferences, getWidenedLiteralType) : inferences;
const baseInferences = widenLiteralTypes ? sameMap(inferences, getWidenedLiteralType) : inferences;
// Infer widened union or supertype, or the unknown type for no common supertype
const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseInferences, /*subtypeReduction*/ true) : getCommonSupertype(baseInferences);
inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
@ -8485,9 +8485,15 @@ namespace ts {
return type.flags & TypeFlags.Anonymous && !!(<AnonymousType>type).elementType;
}
function createFinalArrayType(elementType: Type) {
return createArrayType(elementType !== neverType ?
getUnionType([elementType], /*subtypeReduction*/ true) :
strictNullChecks ? neverType : undefinedWideningType);
}
// We perform subtype reduction upon obtaining the final array type from an evolving array type.
function getFinalArrayType(evolvingArrayType: AnonymousType): Type {
return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createArrayType(getUnionType([evolvingArrayType.elementType], /*subtypeReduction*/ true)));
return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType));
}
function finalizeEvolvingArrayType(type: Type): Type {
@ -8504,7 +8510,7 @@ namespace ts {
function getUnionOrEvolvingArrayType(types: Type[], subtypeReduction: boolean) {
return types.length && every(types, isEvolvingArrayType) ?
getEvolvingArrayType(getUnionType(map(<AnonymousType[]>types, getElementTypeOfEvolvingArrayType))) :
getUnionType(map(types, finalizeEvolvingArrayType), subtypeReduction);
getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction);
}
// Return true if the given node is 'x' in an 'x.push(value)' operation.
@ -8754,7 +8760,7 @@ namespace ts {
// junction is always the non-looping control flow path that leads to the top.
for (let i = flowLoopStart; i < flowLoopCount; i++) {
if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key) {
return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], false), /*incomplete*/ true);
return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], /*subtypeReduction*/ false), /*incomplete*/ true);
}
}
// Add the flow loop junction and reference to the in-process stack and analyze
@ -10728,7 +10734,7 @@ namespace ts {
}
}
return getUnionType(signatures.map(getReturnTypeOfSignature), /*subtypeReduction*/ true);
return getUnionType(map(signatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
}
/// e.g. "props" for React.d.ts,
@ -10778,7 +10784,7 @@ namespace ts {
}
if (elemType.flags & TypeFlags.Union) {
const types = (<UnionOrIntersectionType>elemType).types;
return getUnionType(types.map(type => {
return getUnionType(map(types, type => {
return getResolvedJsxType(node, type, elemClassType);
}), /*subtypeReduction*/ true);
}

View File

@ -257,13 +257,33 @@ namespace ts {
if (array) {
result = [];
for (let i = 0; i < array.length; i++) {
const v = array[i];
result.push(f(v, i));
result.push(f(array[i], i));
}
}
return result;
}
// Maps from T to T and avoids allocation of all elements map to themselves
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[] {
let result: T[];
if (array) {
for (let i = 0; i < array.length; i++) {
if (result) {
result.push(f(array[i], i));
}
else {
const item = array[i];
const mapped = f(item, i);
if (item !== mapped) {
result = array.slice(0, i);
result.push(mapped);
}
}
}
}
return result || array;
}
/**
* Flattens an array containing a mix of array or non-array elements.
*