Optimize getTypeWithFacts

This commit is contained in:
Anders Hejlsberg 2016-08-11 13:44:51 -07:00
parent 24d8d848f1
commit a3845a95d5

View file

@ -7924,6 +7924,14 @@ namespace ts {
return result; return result;
} }
function isFunctionObjectType(type: ObjectType): boolean {
// We do a quick check for a "bind" property before performing the more expensive subtype
// check. This gives us a quicker out in the common case where an object type is not a function.
const resolved = resolveStructuredTypeMembers(type);
return !!(resolved.callSignatures.length || resolved.constructSignatures.length ||
hasProperty(resolved.members, "bind") && isTypeSubtypeOf(type, globalFunctionType));
}
function getTypeFacts(type: Type): TypeFacts { function getTypeFacts(type: Type): TypeFacts {
const flags = type.flags; const flags = type.flags;
if (flags & TypeFlags.String) { if (flags & TypeFlags.String) {
@ -7952,8 +7960,7 @@ namespace ts {
type === falseType ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; type === falseType ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
} }
if (flags & TypeFlags.ObjectType) { if (flags & TypeFlags.ObjectType) {
const resolved = resolveStructuredTypeMembers(type); return isFunctionObjectType(<ObjectType>type) ?
return resolved.callSignatures.length || resolved.constructSignatures.length || isTypeSubtypeOf(type, globalFunctionType) ?
strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
} }
@ -7980,23 +7987,23 @@ namespace ts {
if (!(type.flags & TypeFlags.Union)) { if (!(type.flags & TypeFlags.Union)) {
return getTypeFacts(type) & include ? type : neverType; return getTypeFacts(type) & include ? type : neverType;
} }
let firstType: Type; const types = (<UnionType>type).types;
let types: Type[]; const length = types.length;
for (const t of (type as UnionType).types) { let i = 0;
if (getTypeFacts(t) & include) { while (i < length && getTypeFacts(types[i]) & include) i++;
if (!firstType) { if (i === length) {
firstType = t; return type;
}
else {
if (!types) {
types = [firstType];
}
types.push(t);
}
}
} }
return types ? getUnionType(types) : const filtered = types.slice(0, i);
firstType ? firstType : neverType; i++;
while (i < length) {
const t = types[i];
if (getTypeFacts(t) & include) {
filtered.push(t);
}
i++;
}
return getUnionType(filtered);
} }
function getTypeWithDefault(type: Type, defaultExpression: Expression) { function getTypeWithDefault(type: Type, defaultExpression: Expression) {
@ -8175,14 +8182,14 @@ namespace ts {
if (!(type.flags & TypeFlags.Union)) { if (!(type.flags & TypeFlags.Union)) {
return f(type) ? type : neverType; return f(type) ? type : neverType;
} }
let types = (<UnionType>type).types; const types = (<UnionType>type).types;
let length = types.length; const length = types.length;
let i = 0; let i = 0;
while (i < length && f(types[i])) i++; while (i < length && f(types[i])) i++;
if (i === length) { if (i === length) {
return type; return type;
} }
let filtered = types.slice(0, i); const filtered = types.slice(0, i);
i++; i++;
while (i < length) { while (i < length) {
const t = types[i]; const t = types[i];