diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyDescriptorTypeUtil.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyDescriptorTypeUtil.java index ab77dc5b0198..8ddf38d79231 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyDescriptorTypeUtil.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyDescriptorTypeUtil.java @@ -71,7 +71,7 @@ public final class PyDescriptorTypeUtil { } else { instanceArgumentType = classType; - instanceTypeArgument = noneType; + instanceTypeArgument = classType.toClass(); } List argumentTypes = List.of(instanceArgumentType, instanceTypeArgument); PyType type = PySyntheticCallHelper.getCallTypeByFunctionName(PyNames.DUNDER_GET, receiverType, argumentTypes, context); diff --git a/python/testSrc/com/jetbrains/python/types/PyAttributeAndDescriptorTypeTest.kt b/python/testSrc/com/jetbrains/python/types/PyAttributeAndDescriptorTypeTest.kt index d3ec23622b60..7ae933e98000 100644 --- a/python/testSrc/com/jetbrains/python/types/PyAttributeAndDescriptorTypeTest.kt +++ b/python/testSrc/com/jetbrains/python/types/PyAttributeAndDescriptorTypeTest.kt @@ -1188,6 +1188,38 @@ class PyAttributeAndDescriptorTypeTest : PyCodeInsightTestCase() { # └ TYPE list """) + @Test + @TestFor(issues = ["PY-63737"]) + fun `generic descriptor with own type parameter in get binds the return type variable on instance access`() = test(""" + from typing import Callable, TypeVar, Generic + T = TypeVar("T") + T_co = TypeVar("T_co", covariant=True) + class CachedSlotProperty(Generic[T, T_co]): + def __init__(self, f: Callable[[T], T_co]) -> None: + self.f = f + def __get__(self, instance: T, owner: type[T]) -> T_co: + return self.f(instance) + 1 + class Foo: + @CachedSlotProperty + def bar(self) -> int: + return 42 + expr = Foo().bar + #└ TYPE int + """) + + @Test + @TestFor(issues = ["PY-63737"]) + fun `instance access passes the owner class so a get typed with type T does not drop other bindings`() = test(""" + from typing import Callable + class CachedSlotProperty[T, V]: + def __init__(self, f: Callable[[T], V]) -> None: ... + def __get__(self, instance: T, owner: type[T]) -> V: ... + class Foo: + bar: CachedSlotProperty[Foo, int] + expr = Foo().bar + #└ TYPE int + """) + @Test @TestFor(issues = ["PY-63737"]) fun `generic descriptor subclass used as decorator accessed on instance`() = test("""