Improved type evaluation performance in certain cases involving protocol matching for complex, nested protocols. This addresses #9109. (#9115)

This commit is contained in:
Eric Traut 2024-09-30 14:30:09 -07:00 committed by GitHub
parent 6b19e98d26
commit 0b02230dde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 9 additions and 33 deletions

View File

@ -237,14 +237,6 @@ export class ConstraintTracker {
}
}
isSame(other: ConstraintTracker) {
if (other._constraintSets.length !== this._constraintSets.length) {
return false;
}
return this._constraintSets.every((set, index) => set.isSame(other._constraintSets[index]));
}
isEmpty() {
return this._constraintSets.every((set) => set.isEmpty());
}

View File

@ -58,7 +58,6 @@ interface ProtocolCompatibility {
srcType: Type;
destType: Type;
flags: AssignTypeFlags;
constraints: ConstraintTracker | undefined;
isCompatible: boolean;
}
@ -80,6 +79,12 @@ export function assignClassToProtocol(
// srcType can be an instantiable class or a class instance.
assert(isInstantiableClass(destType) && ClassType.isProtocolClass(destType));
// A literal source type should never affect protocol matching, so strip
// the literal type if it's present. This helps conserve on cache entries.
if (srcType.priv.literalValue !== undefined) {
srcType = evaluator.stripLiteralValue(srcType) as ClassType;
}
const enforceInvariance = (flags & AssignTypeFlags.Invariant) !== 0;
// Use a stack of pending protocol class evaluations to detect recursion.
@ -120,7 +125,6 @@ export function assignClassToProtocol(
protocolAssignmentStack.push({ srcType, destType });
let isCompatible = true;
const clonedConstraints = constraints?.clone();
try {
isCompatible = assignToProtocolInternal(evaluator, destType, srcType, diag, constraints, flags, recursionCount);
@ -134,7 +138,7 @@ export function assignClassToProtocol(
protocolAssignmentStack.pop();
// Cache the results for next time.
setProtocolCompatibility(destType, srcType, flags, clonedConstraints, isCompatible);
setProtocolCompatibility(destType, srcType, flags, isCompatible);
return isCompatible;
}
@ -225,12 +229,7 @@ function getProtocolCompatibility(
}
const entry = entries.find((entry) => {
return (
isTypeSame(entry.destType, destType) &&
isTypeSame(entry.srcType, srcType) &&
entry.flags === flags &&
isConstraintTrackerSame(constraints, entry.constraints)
);
return isTypeSame(entry.destType, destType) && isTypeSame(entry.srcType, srcType) && entry.flags === flags;
});
return entry?.isCompatible;
@ -240,7 +239,6 @@ function setProtocolCompatibility(
destType: ClassType,
srcType: ClassType,
flags: AssignTypeFlags,
constraints: ConstraintTracker | undefined,
isCompatible: boolean
) {
let map = srcType.shared.protocolCompatibility as Map<string, ProtocolCompatibility[]> | undefined;
@ -255,27 +253,13 @@ function setProtocolCompatibility(
map.set(destType.shared.fullName, entries);
}
entries.push({
destType,
srcType,
flags,
constraints: constraints,
isCompatible,
});
entries.push({ destType, srcType, flags, isCompatible });
if (entries.length > maxProtocolCompatibilityCacheEntries) {
entries.shift();
}
}
function isConstraintTrackerSame(context1: ConstraintTracker | undefined, context2: ConstraintTracker | undefined) {
if (!context1 || !context2) {
return context1 === context2;
}
return context1.isSame(context2);
}
function assignToProtocolInternal(
evaluator: TypeEvaluator,
destType: ClassType,