Skip to content

Commit 451f48b

Browse files
committed
Optimize checkTypeRelatedTo, part 2
1 parent f5f8a45 commit 451f48b

2 files changed

Lines changed: 44 additions & 77 deletions

File tree

src/compiler/checker.ts

Lines changed: 43 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -5832,14 +5832,16 @@ namespace ts {
58325832
return compareSignaturesRelated(source, target, ignoreReturnTypes, /*reportErrors*/ false, /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False;
58335833
}
58345834

5835+
type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void;
5836+
58355837
/**
58365838
* See signatureRelatedTo, compareSignaturesIdentical
58375839
*/
58385840
function compareSignaturesRelated(source: Signature,
58395841
target: Signature,
58405842
ignoreReturnTypes: boolean,
58415843
reportErrors: boolean,
5842-
errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void,
5844+
errorReporter: ErrorReporter,
58435845
compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary {
58445846
// TODO (drosen): De-duplicate code between related functions.
58455847
if (source === target) {
@@ -5924,7 +5926,7 @@ namespace ts {
59245926
function compareTypePredicateRelatedTo(source: TypePredicate,
59255927
target: TypePredicate,
59265928
reportErrors: boolean,
5927-
errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void,
5929+
errorReporter: ErrorReporter,
59285930
compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary {
59295931
if (source.kind !== target.kind) {
59305932
if (reportErrors) {
@@ -5961,8 +5963,8 @@ namespace ts {
59615963
const sourceReturnType = getReturnTypeOfSignature(erasedSource);
59625964
const targetReturnType = getReturnTypeOfSignature(erasedTarget);
59635965
if (targetReturnType === voidType
5964-
|| checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
5965-
|| checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
5966+
|| isTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation)
5967+
|| isTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation)) {
59665968

59675969
return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true);
59685970
}
@@ -5996,49 +5998,60 @@ namespace ts {
59965998
}
59975999
}
59986000

5999-
function isPrimtiveTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
6000-
if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return true;
6001-
if (source.flags & TypeFlags.Undefined) {
6002-
if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void)) return true;
6001+
function isEnumTypeRelatedTo(source: Type, target: Type, errorReporter?: ErrorReporter) {
6002+
if (source.symbol.flags & SymbolFlags.EnumMember && source.symbol.parent === target.symbol) {
6003+
return true;
60036004
}
6004-
if (source.flags & TypeFlags.Null) {
6005-
if (!strictNullChecks || target.flags & TypeFlags.Null) return true;
6005+
if (source.symbol.name !== target.symbol.name || !(source.symbol.flags & SymbolFlags.RegularEnum) || !(target.symbol.flags & SymbolFlags.RegularEnum)) {
6006+
return false;
60066007
}
6007-
if (source.flags & TypeFlags.NumberLike && target === numberType) return true;
6008-
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && source.symbol.flags & SymbolFlags.EnumMember && source.symbol.parent === target.symbol) {
6009-
return true;
6008+
const targetEnumType = getTypeOfSymbol(target.symbol);
6009+
for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) {
6010+
if (property.flags & SymbolFlags.EnumMember) {
6011+
const targetProperty = getPropertyOfType(targetEnumType, property.name);
6012+
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
6013+
if (errorReporter) {
6014+
errorReporter(Diagnostics.Property_0_is_missing_in_type_1, property.name,
6015+
typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
6016+
}
6017+
return false;
6018+
}
6019+
}
60106020
}
6011-
if (source.flags & TypeFlags.StringLike && target === stringType) return true;
6021+
return true;
6022+
}
6023+
6024+
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorReporter?: ErrorReporter) {
6025+
if (target.flags & TypeFlags.Never) return false;
6026+
if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return true;
6027+
if (source.flags & TypeFlags.StringLike && target.flags & TypeFlags.String) return true;
6028+
if (source.flags & TypeFlags.NumberLike && target.flags & TypeFlags.Number) return true;
6029+
if (source.flags & TypeFlags.BooleanLike && target.flags & TypeFlags.Boolean) return true;
6030+
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source, target, errorReporter)) return true;
6031+
if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true;
6032+
if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true;
60126033
if (relation === assignableRelation || relation === comparableRelation) {
60136034
if (source.flags & TypeFlags.Any) return true;
6014-
if (source === numberType && target.flags & TypeFlags.Enum) return true;
6035+
if (source.flags & TypeFlags.Number && target.flags & TypeFlags.Enum) return true;
60156036
}
6016-
if (source.flags & TypeFlags.BooleanLike && target.flags & TypeFlags.Boolean) return true;
60176037
return false;
60186038
}
60196039

60206040
function isTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
6021-
if (source === target) {
6041+
if (source === target || relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
60226042
return true;
60236043
}
6024-
if (relation !== identityRelation) {
6025-
if (source.flags & TypeFlags.Primitive && target.flags & TypeFlags.Primitive) {
6026-
if (isPrimtiveTypeRelatedTo(source, target, relation)) {
6027-
return true;
6028-
}
6029-
if (!(source.flags & TypeFlags.Union || target.flags & TypeFlags.Union)) {
6030-
return false;
6031-
}
6032-
}
6033-
}
60346044
if (source.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) {
60356045
const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
60366046
const related = relation[id];
60376047
if (related !== undefined) {
60386048
return related === RelationComparisonResult.Succeeded;
60396049
}
60406050
}
6041-
return checkTypeRelatedTo(source, target, relation, undefined, undefined, undefined);
6051+
if (source.flags & TypeFlags.StructuredOrTypeParameter || target.flags & TypeFlags.StructuredOrTypeParameter) {
6052+
return checkTypeRelatedTo(source, target, relation, undefined, undefined, undefined);
6053+
}
6054+
return false;
60426055
}
60436056

60446057
/**
@@ -6112,33 +6125,12 @@ namespace ts {
61126125
let result: Ternary;
61136126
// both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
61146127
if (source === target) return Ternary.True;
6128+
61156129
if (relation === identityRelation) {
61166130
return isIdenticalTo(source, target);
61176131
}
61186132

6119-
if (!(target.flags & TypeFlags.Never)) {
6120-
if (target.flags & TypeFlags.Any || source.flags & TypeFlags.Never) return Ternary.True;
6121-
if (source.flags & TypeFlags.Undefined) {
6122-
if (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void)) return Ternary.True;
6123-
}
6124-
if (source.flags & TypeFlags.Null) {
6125-
if (!strictNullChecks || target.flags & TypeFlags.Null) return Ternary.True;
6126-
}
6127-
if (source.flags & TypeFlags.NumberLike && target === numberType) return Ternary.True;
6128-
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
6129-
if (result = enumRelatedTo(source, target, reportErrors)) {
6130-
return result;
6131-
}
6132-
}
6133-
if (source.flags & TypeFlags.StringLike && target === stringType) return Ternary.True;
6134-
if (relation === assignableRelation || relation === comparableRelation) {
6135-
if (source.flags & TypeFlags.Any) return Ternary.True;
6136-
if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True;
6137-
}
6138-
if (source.flags & TypeFlags.BooleanLike && target.flags & TypeFlags.Boolean) {
6139-
return Ternary.True;
6140-
}
6141-
}
6133+
if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
61426134

61436135
if (source.flags & TypeFlags.FreshObjectLiteral) {
61446136
if (hasExcessProperties(<FreshObjectLiteralType>source, target, reportErrors)) {
@@ -6772,32 +6764,6 @@ namespace ts {
67726764
return Ternary.False;
67736765
}
67746766

6775-
function enumRelatedTo(source: Type, target: Type, reportErrors?: boolean) {
6776-
if (source.symbol.flags & SymbolFlags.EnumMember && source.symbol.parent === target.symbol) {
6777-
return Ternary.True;
6778-
}
6779-
if (source.symbol.name !== target.symbol.name ||
6780-
!(source.symbol.flags & SymbolFlags.RegularEnum) ||
6781-
!(target.symbol.flags & SymbolFlags.RegularEnum)) {
6782-
return Ternary.False;
6783-
}
6784-
const targetEnumType = getTypeOfSymbol(target.symbol);
6785-
for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) {
6786-
if (property.flags & SymbolFlags.EnumMember) {
6787-
const targetProperty = getPropertyOfType(targetEnumType, property.name);
6788-
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
6789-
if (reportErrors) {
6790-
reportError(Diagnostics.Property_0_is_missing_in_type_1,
6791-
property.name,
6792-
typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
6793-
}
6794-
return Ternary.False;
6795-
}
6796-
}
6797-
}
6798-
return Ternary.True;
6799-
}
6800-
68016767
function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) {
68026768
if (!sourceSignature.declaration || !targetSignature.declaration) {
68036769
return true;

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,7 @@ namespace ts {
22652265
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
22662266
UnionOrIntersection = Union | Intersection,
22672267
StructuredType = ObjectType | Union | Intersection,
2268+
StructuredOrTypeParameter = StructuredType | TypeParameter,
22682269

22692270
// 'Narrowable' types are types where narrowing actually narrows.
22702271
// This *should* be every type other than null, undefined, void, and never

0 commit comments

Comments
 (0)