Skip to content

Commit

Permalink
Backed out recent performance optimization that resulted in a regress…
Browse files Browse the repository at this point in the history
…ion for protocol matching in certain circumstances. This addresses #9153, #9132, and #9130. (#9164)
  • Loading branch information
erictraut authored Oct 7, 2024
1 parent 649a2ab commit 23b4668
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 3 deletions.
8 changes: 8 additions & 0 deletions packages/pyright-internal/src/analyzer/constraintTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ 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());
}
Expand Down
28 changes: 25 additions & 3 deletions packages/pyright-internal/src/analyzer/protocols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ interface ProtocolCompatibility {
srcType: Type;
destType: Type;
flags: AssignTypeFlags;
constraints: ConstraintTracker | undefined;
isCompatible: boolean;
}

Expand Down Expand Up @@ -125,6 +126,7 @@ export function assignClassToProtocol(

protocolAssignmentStack.push({ srcType, destType });
let isCompatible = true;
const clonedConstraints = constraints?.clone();

try {
isCompatible = assignToProtocolInternal(evaluator, destType, srcType, diag, constraints, flags, recursionCount);
Expand All @@ -138,7 +140,7 @@ export function assignClassToProtocol(
protocolAssignmentStack.pop();

// Cache the results for next time.
setProtocolCompatibility(destType, srcType, flags, isCompatible);
setProtocolCompatibility(destType, srcType, flags, clonedConstraints, isCompatible);

return isCompatible;
}
Expand Down Expand Up @@ -229,7 +231,12 @@ function getProtocolCompatibility(
}

const entry = entries.find((entry) => {
return isTypeSame(entry.destType, destType) && isTypeSame(entry.srcType, srcType) && entry.flags === flags;
return (
isTypeSame(entry.destType, destType) &&
isTypeSame(entry.srcType, srcType) &&
entry.flags === flags &&
isConstraintTrackerSame(constraints, entry.constraints)
);
});

return entry?.isCompatible;
Expand All @@ -239,6 +246,7 @@ function setProtocolCompatibility(
destType: ClassType,
srcType: ClassType,
flags: AssignTypeFlags,
constraints: ConstraintTracker | undefined,
isCompatible: boolean
) {
let map = srcType.shared.protocolCompatibility as Map<string, ProtocolCompatibility[]> | undefined;
Expand All @@ -253,13 +261,27 @@ function setProtocolCompatibility(
map.set(destType.shared.fullName, entries);
}

entries.push({ destType, srcType, flags, isCompatible });
entries.push({
destType,
srcType,
flags,
constraints: constraints,
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,
Expand Down
6 changes: 6 additions & 0 deletions packages/pyright-internal/src/tests/samples/protocol51.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This sample tests a regression case related to the protocol compatibility
# cache.


int(round(1.2, 0))
round(3.4, 2)
6 changes: 6 additions & 0 deletions packages/pyright-internal/src/tests/typeEvaluator7.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,12 @@ test('Protocol50', () => {
TestUtils.validateResults(analysisResults, 0);
});

test('Protocol51', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['protocol51.py']);

TestUtils.validateResults(analysisResults, 0);
});

test('ProtocolExplicit1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['protocolExplicit1.py']);

Expand Down

0 comments on commit 23b4668

Please sign in to comment.