Clean up and reorder getSpreadType body

This commit is contained in:
Nathan Shively-Sanders 2016-10-22 10:08:58 -07:00
parent 485e2490e7
commit 16dfdc49dc

View file

@ -4358,8 +4358,8 @@ namespace ts {
getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly); getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly);
} }
function unionIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo { function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo {
return !info1 ? info2 : !info2 ? info1 : createIndexInfo( return info1 && info2 && createIndexInfo(
getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly);
} }
@ -5760,12 +5760,14 @@ namespace ts {
for (const member of (node as TypeLiteralNode).members) { for (const member of (node as TypeLiteralNode).members) {
if (member.kind === SyntaxKind.SpreadTypeElement) { if (member.kind === SyntaxKind.SpreadTypeElement) {
if (members) { 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; members = undefined;
stringIndexInfo = undefined; stringIndexInfo = undefined;
numberIndexInfo = 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) { else if (member.kind === SyntaxKind.IndexSignature) {
const index = member as IndexSignatureDeclaration; const index = member as IndexSignatureDeclaration;
@ -5798,75 +5800,77 @@ namespace ts {
} }
} }
if (members || stringIndexInfo || numberIndexInfo) { 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; 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 // TODO: Reorder everything now that it's order independent, to be easier to read
const id = getTypeListId([left, right]); const id = getTypeListId([left, right]);
if (id in spreadTypes) { if (id in spreadTypes) {
return spreadTypes[id]; return spreadTypes[id];
} }
if (right.flags & TypeFlags.Any) {
// non-spreadable types
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
return anyType; return anyType;
} }
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 => getSpreadType(left, t, symbol, aliasSymbol, aliasTypeArguments));
return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments);
}
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.ObjectType &&
(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);
}
if (right.flags & TypeFlags.Spread) { if (right.flags & TypeFlags.Spread) {
// spread is right associative and associativity applies, so transform // spread is right associative and associativity applies, so transform
// (T ... U) ... V to T ... (U ... V) // (T ... U) ... V to T ... (U ... V)
const rspread = right as SpreadType; const rspread = right as SpreadType;
if (rspread.left === emptyObjectType) { if (rspread.left === emptyObjectType) {
return getSpreadTypeWorker(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments); // U ... ({} ... T) => (U ... T)
return getSpreadType(left, rspread.right, symbol, aliasSymbol, aliasTypeArguments);
} }
return getSpreadTypeWorker(getSpreadTypeWorker(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments), return getSpreadType(getSpreadType(left, rspread.left, symbol, aliasSymbol, aliasTypeArguments),
rspread.right, 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 => getSpreadTypeWorker(left, t, symbol, aliasSymbol, aliasTypeArguments));
return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments);
}
if (right.flags & TypeFlags.Primitive || left.flags & TypeFlags.Any) {
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.ObjectType && // create an object type if left and right are both objects,
left.flags & TypeFlags.Spread && // otherwise create a spread type
(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);
}
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.ObjectType && left.flags & TypeFlags.ObjectType) { if (right.flags & TypeFlags.ObjectType && left.flags & TypeFlags.ObjectType) {
const members = createMap<Symbol>(); const members = createMap<Symbol>();
const skippedPrivateMembers = createMap<boolean>(); const skippedPrivateMembers = createMap<boolean>();
const stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String));
// TODO: This is pretty ugly const numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number));
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; const isFromSpread = right.symbol !== symbol;
for (const rightProp of getPropertiesOfType(right)) { for (const rightProp of getPropertiesOfType(right)) {
@ -6339,7 +6343,7 @@ namespace ts {
} }
if (type.flags & TypeFlags.Spread) { if (type.flags & TypeFlags.Spread) {
const spread = type as SpreadType; 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; return type;
@ -10933,7 +10937,7 @@ namespace ts {
} }
else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) { else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) {
if (propertiesArray.length > 0) { if (propertiesArray.length > 0) {
spread = getSpreadTypeWorker(spread, createObjectLiteralType(), node.symbol); spread = getSpreadType(spread, createObjectLiteralType(), node.symbol);
propertiesArray = []; propertiesArray = [];
propertiesTable = createMap<Symbol>(); propertiesTable = createMap<Symbol>();
hasComputedStringProperty = false; hasComputedStringProperty = false;
@ -10941,7 +10945,7 @@ namespace ts {
typeFlags = 0; typeFlags = 0;
} }
const type = checkExpression((memberDecl as SpreadElementExpression).expression); const type = checkExpression((memberDecl as SpreadElementExpression).expression);
spread = getSpreadTypeWorker(spread, type, node.symbol); spread = getSpreadType(spread, type, node.symbol);
continue; continue;
} }
else { else {
@ -10985,9 +10989,8 @@ namespace ts {
if (spread !== emptyObjectType) { if (spread !== emptyObjectType) {
if (propertiesArray.length > 0) { 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; spread.flags |= propagatedFlags;
return spread; return spread;
} }