Skip to content

Commit

Permalink
Fix overlap check for ParamSpec types
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
JukkaL committed Oct 25, 2024
1 parent 1cb8cc4 commit ee361ec
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
6 changes: 5 additions & 1 deletion mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
38 changes: 38 additions & 0 deletions test-data/unit/check-selftype.test
Original file line number Diff line number Diff line change
Expand Up @@ -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]

0 comments on commit ee361ec

Please sign in to comment.