From ee361ec2007a230833804bd54dc8cec0590732cf Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 25 Oct 2024 12:09:12 +0100 Subject: [PATCH] Fix overlap check for ParamSpec types ParamSpec types can match arbitrary parameter types, so treat them as having 'object' as the upper bound. This also fixes issues with filtering of overload items based on self type. Fixes #18036. --- mypy/meet.py | 6 ++++- test-data/unit/check-selftype.test | 38 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/mypy/meet.py b/mypy/meet.py index d614ecc45a57..f51d354d8f2f 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -223,7 +223,11 @@ def get_possible_variants(typ: Type) -> list[Type]: else: return [typ.upper_bound] elif isinstance(typ, ParamSpecType): - return [typ.upper_bound] + # Extract 'object' from the final mro item + upper_bound = get_proper_type(typ.upper_bound) + if isinstance(upper_bound, Instance): + return [Instance(upper_bound.type.mro[-1], [])] + return [AnyType(TypeOfAny.implementation_artifact)] elif isinstance(typ, TypeVarTupleType): return [typ.upper_bound] elif isinstance(typ, UnionType): diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 1a088fe05092..fa853ac48e5a 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -2176,3 +2176,41 @@ class count: def foo(x: Union[range[int], count]) -> None: for item in x: reveal_type(item) # N: Revealed type is "builtins.int" + +[case testGenericDescriptorWithSelfTypeAnnotationsAndOverloads] +from __future__ import annotations +from typing import Any, overload, Callable, TypeVar, Generic, ParamSpec +from typing_extensions import Concatenate + +C = TypeVar("C", bound=Callable[..., Any]) +S = TypeVar("S") +P = ParamSpec("P") +R = TypeVar("R") + +class Descriptor(Generic[C]): + def __init__(self, impl: C) -> None: ... + + @overload + def __get__( + self: Descriptor[C], instance: None, owner: type | None + ) -> Descriptor[C]: ... + + @overload + def __get__( + self: Descriptor[Callable[Concatenate[S, P], R]], instance: S, owner: type | None, + ) -> Callable[P, R]: ... + + def __get__(self, *args, **kwargs): ... + +class Test: + @Descriptor + def method(self, foo: int, bar: str) -> bytes: ... + +reveal_type(Test().method) # N: Revealed type is "def (foo: builtins.int, bar: builtins.str) -> builtins.bytes" + +class Test2: + @Descriptor + def method(self, foo: int, *, bar: str) -> bytes: ... + +reveal_type(Test2().method) # N: Revealed type is "def (foo: builtins.int, *, bar: builtins.str) -> builtins.bytes" +[builtins fixtures/tuple.pyi]