Simplify logic in checkTypeRelatedTo

This commit is contained in:
Anders Hejlsberg
2016-10-18 14:13:19 -07:00
parent eb7d2cbe9b
commit 6a0f72916e

View File

@@ -5622,7 +5622,6 @@ namespace ts {
if (type.flags & TypeFlags.Union) {
// We are attempting to construct a type of the form X & (A | B) & Y. Transform this into a type of
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
let unionType = <UnionType>types[i];
return getUnionType(map((<UnionType>type).types, t => getIntersectionType(replaceElement(types, i, t))),
/*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments);
}
@@ -6574,7 +6573,9 @@ namespace ts {
const saveErrorInfo = errorInfo;
// Note that these checks are specifically ordered to produce correct results.
// Note that these checks are specifically ordered to produce correct results. In particular,
// we need to deconstruct unions before intersections (because unions are always at the top),
// and we need to handle "each" relations before "some" relations for the same kind of type.
if (source.flags & TypeFlags.Union) {
if (relation === comparableRelation) {
result = someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
@@ -6582,44 +6583,36 @@ namespace ts {
else {
result = eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
}
if (result) {
return result;
}
}
else if (target.flags & TypeFlags.Union) {
if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive))) {
return result;
}
}
else if (target.flags & TypeFlags.Intersection) {
result = typeRelatedToEachType(source, target as IntersectionType, reportErrors);
if (result) {
if (result = typeRelatedToEachType(source, target as IntersectionType, reportErrors)) {
return result;
}
}
else {
// It is necessary to try these "some" checks on both sides because there may be nested "each" checks
// on either side that need to be prioritized. For example, A | B = (A | B) & (C | D) or
// A & B = (A & B) | (C & D).
if (source.flags & TypeFlags.Intersection) {
// Check to see if any constituents of the intersection are immediately related to the target.
//
// Don't report errors though. Checking whether a constituent is related to the source is not actually
// useful and leads to some confusing error messages. Instead it is better to let the below checks
// take care of this, or to not elaborate at all. For instance,
//
// - For an object type (such as 'C = A & B'), users are usually more interested in structural errors.
//
// - For a union type (such as '(A | B) = (C & D)'), it's better to hold onto the whole intersection
// than to report that 'D' is not assignable to 'A' or 'B'.
//
// - For a primitive type or type parameter (such as 'number = A & B') there is no point in
// breaking the intersection apart.
if (result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false)) {
return result;
}
}
if (target.flags & TypeFlags.Union) {
if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive))) {
return result;
}
else if (source.flags & TypeFlags.Intersection) {
// Check to see if any constituents of the intersection are immediately related to the target.
//
// Don't report errors though. Checking whether a constituent is related to the source is not actually
// useful and leads to some confusing error messages. Instead it is better to let the below checks
// take care of this, or to not elaborate at all. For instance,
//
// - For an object type (such as 'C = A & B'), users are usually more interested in structural errors.
//
// - For a union type (such as '(A | B) = (C & D)'), it's better to hold onto the whole intersection
// than to report that 'D' is not assignable to 'A' or 'B'.
//
// - For a primitive type or type parameter (such as 'number = A & B') there is no point in
// breaking the intersection apart.
if (result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false)) {
return result;
}
}