Skip to content

Commit

Permalink
Fixed bug that results in incorrect type evaluation when performing p…
Browse files Browse the repository at this point in the history
…rotocol matching that involves an attribute with a callable type parameterized by a ParamSpec. This addresses #9330. (#9344)
  • Loading branch information
erictraut authored Oct 28, 2024
1 parent 471f76b commit 901c75f
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/analyzer/protocols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ function assignToProtocolInternal(
destMemberType = applySolvedTypeVars(destMemberType, selfSolution);

// If the dest is a method, bind it.
if (isFunction(destMemberType) || isOverloaded(destMemberType)) {
if (!destSymbol.isInstanceMember() && (isFunction(destMemberType) || isOverloaded(destMemberType))) {
let boundDeclaredType: FunctionType | OverloadedType | undefined;

// Functions are considered read-only.
Expand Down
24 changes: 24 additions & 0 deletions packages/pyright-internal/src/tests/samples/protocol52.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This sample tests the case where a protocol includes a callable
# attribute that is an instance variable. It shouldn't be bound
# to the concrete class in this case.

from typing import Callable, Protocol


class A:
def __init__(self, *, p1: int, p2: str) -> None: ...


class ProtoB[**P, T](Protocol):
x: Callable[P, T]


class B:
x: type[A]


def func1[**P, T](v: ProtoB[P, T]) -> Callable[P, T]: ...


x1 = func1(B())
reveal_type(x1, expected_text="(*, p1: int, p2: str) -> A")
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 @@ -605,6 +605,12 @@ test('Protocol51', () => {
TestUtils.validateResults(analysisResults, 0);
});

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

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

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

Expand Down

0 comments on commit 901c75f

Please sign in to comment.