Skip to content

Commit

Permalink
Remove simplification logic from getConditionalType + simplify substi…
Browse files Browse the repository at this point in the history
…tution types
  • Loading branch information
ahejlsberg committed May 13, 2019
1 parent 4e040f7 commit 1b3589b
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 38 deletions.
47 changes: 10 additions & 37 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10196,6 +10196,7 @@ namespace ts {
function getSimplifiedType(type: Type, writing: boolean): Type {
return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(<IndexedAccessType>type, writing) :
type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(<ConditionalType>type, writing) :
type.flags & TypeFlags.Substitution ? writing ? (<SubstitutionType>type).typeVariable : (<SubstitutionType>type).substitute :
type;
}

Expand Down Expand Up @@ -10260,10 +10261,10 @@ namespace ts {
}

function getSimplifiedConditionalType(type: ConditionalType, writing: boolean) {
const falseType = getFalseTypeFromConditionalType(type);
const trueType = getTrueTypeFromConditionalType(type);
const checkType = type.checkType;
const extendsType = type.extendsType;
const trueType = getTrueTypeFromConditionalType(type);
const falseType = getFalseTypeFromConditionalType(type);
// Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`.
if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) {
if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true
Expand All @@ -10281,10 +10282,16 @@ namespace ts {
return getSimplifiedType(falseType, writing);
}
}

return type;
}

/**
* Invokes union simplification logic to determine if an intersection is considered empty as a union constituent
*/
function isIntersectionEmpty(type1: Type, type2: Type) {
return !!(getUnionType([intersectTypes(type1, type2), neverType]).flags & TypeFlags.Never);
}

function substituteIndexedMappedType(objectType: MappedType, index: Type) {
const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]);
const templateMapper = combineTypeMappers(objectType.mapper, mapper);
Expand Down Expand Up @@ -10391,36 +10398,12 @@ namespace ts {
return type;
}

/**
* Invokes union simplification logic to determine if an intersection is considered empty as a union constituent
*/
function isIntersectionEmpty(type1: Type, type2: Type) {
return !!(getUnionType([intersectTypes(type1, type2), neverType]).flags & TypeFlags.Never);
}

function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined): Type {
const checkType = instantiateType(root.checkType, mapper);
const extendsType = instantiateType(root.extendsType, mapper);
if (checkType === wildcardType || extendsType === wildcardType) {
return wildcardType;
}
// Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`.
if (root.falseType.flags & TypeFlags.Never && getActualTypeVariable(root.trueType) === getActualTypeVariable(root.checkType)) {
if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true
return checkType;
}
else if (isIntersectionEmpty(checkType, extendsType)) { // Always false
return neverType;
}
}
else if (root.trueType.flags & TypeFlags.Never && getActualTypeVariable(root.falseType) === getActualTypeVariable(root.checkType)) {
if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true
return neverType;
}
else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false
return checkType;
}
}
const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable | TypeFlags.GenericMappedType);
let combinedMapper: TypeMapper | undefined;
if (root.inferTypeParameters) {
Expand Down Expand Up @@ -10461,10 +10444,6 @@ namespace ts {
}
}
// Return a deferred type for a check that is neither definitely true nor definitely false
return getDeferredConditionalType(root, mapper, combinedMapper, checkType, extendsType);
}

function getDeferredConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, combinedMapper: TypeMapper | undefined, checkType: Type, extendsType: Type) {
const erasedCheckType = getActualTypeVariable(checkType);
const result = <ConditionalType>createType(TypeFlags.Conditional);
result.root = root;
Expand Down Expand Up @@ -12453,12 +12432,6 @@ namespace ts {
if (isFreshLiteralType(target)) {
target = (<FreshableType>target).regularType;
}
if (source.flags & TypeFlags.Substitution) {
source = (<SubstitutionType>source).substitute;
}
if (target.flags & TypeFlags.Substitution) {
target = (<SubstitutionType>target).typeVariable;
}
if (source.flags & TypeFlags.Simplifiable) {
source = getSimplifiedType(source, /*writing*/ false);
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3967,7 +3967,7 @@ namespace ts {
/* @internal */
ObjectFlagsType = Nullable | Never | Object | Union | Intersection,
/* @internal */
Simplifiable = IndexedAccess | Conditional,
Simplifiable = IndexedAccess | Conditional | Substitution,
// 'Narrowable' types are types where narrowing actually narrows.
// This *should* be every type other than null, undefined, void, and never
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
Expand Down

0 comments on commit 1b3589b

Please sign in to comment.