Skip to content

Commit 60a4f35

Browse files
authored
Implement Overloaded. (#92)
1 parent f3d2c59 commit 60a4f35

4 files changed

Lines changed: 73 additions & 1 deletion

File tree

tests/test_type_eval.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
TypeVar,
1717
Union,
1818
get_args,
19+
overload,
1920
)
2021

2122
import pytest
@@ -45,6 +46,7 @@
4546
Member,
4647
Members,
4748
NewProtocol,
49+
Overloaded,
4850
Param,
4951
Slice,
5052
SpecialFormEllipsis,
@@ -466,6 +468,46 @@ def f[T](self, x: T) -> OnlyIntToSet[T]: ...
466468
)
467469

468470

471+
def test_getmember_04():
472+
class C:
473+
@overload
474+
def f(self, x: int) -> set[int]: ...
475+
476+
@overload
477+
def f[T](self, x: T) -> T: ...
478+
479+
def f(self, x): ...
480+
481+
m = eval_typing(GetMember[C, Literal["f"]])
482+
mt = eval_typing(GetType[m])
483+
assert mt.__origin__ is Overloaded
484+
assert len(mt.__args__) == 2
485+
486+
# Non-generic overload
487+
assert (
488+
eval_typing(IsAssignable[GetArg[mt, Overloaded, Literal[0]], Callable])
489+
== _BoolLiteral[True]
490+
)
491+
assert (
492+
mt.__args__[0]
493+
== Callable[
494+
[Param[Literal["self"], C], Param[Literal["x"], int]], set[int]
495+
]
496+
)
497+
498+
# Generic overload
499+
assert (
500+
eval_typing(
501+
IsAssignable[GetArg[mt, Overloaded, Literal[1]], GenericCallable]
502+
)
503+
== _BoolLiteral[True]
504+
)
505+
assert (
506+
eval_typing(mt.__args__[1].__args__[1](int))
507+
== Callable[[Param[Literal["self"], C], Param[Literal["x"], int]], int]
508+
)
509+
510+
469511
def test_getarg_never():
470512
d = eval_typing(GetArg[Never, object, Literal[0]])
471513
assert d is Never

typemap/type_eval/_apply_generic.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,14 @@ def _resolved_function_signature(func, args):
291291
return sig
292292

293293

294-
def get_local_defns(boxed: Boxed) -> tuple[dict[str, Any], dict[str, Any]]:
294+
def get_local_defns(
295+
boxed: Boxed,
296+
) -> tuple[
297+
dict[str, Any],
298+
dict[
299+
str, types.FunctionType | classmethod | staticmethod | WrappedOverloads
300+
],
301+
]:
295302
from typemap.typing import GenericCallable
296303

297304
annos: dict[str, Any] = {}
@@ -327,6 +334,8 @@ def get_local_defns(boxed: Boxed) -> tuple[dict[str, Any], dict[str, Any]]:
327334
# XXX: This is totally wrong; we still need to do
328335
# substitute in class vars
329336
local_fn = stuff
337+
elif overloads := typing.get_overloads(stuff):
338+
local_fn = WrappedOverloads(tuple(overloads))
330339

331340
# If we got stuck, we build a GenericCallable that
332341
# computes the type once it has been given type
@@ -370,6 +379,11 @@ def lam(*vs):
370379
return annos, dct
371380

372381

382+
@dataclasses.dataclass(frozen=True)
383+
class WrappedOverloads:
384+
functions: tuple[typing.Callable[..., Any], ...]
385+
386+
373387
def flatten_class_new_proto(cls: type) -> type:
374388
# This is a hacky version of flatten_class that works by using
375389
# NewProtocol on Members!

typemap/type_eval/_eval_operators.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
Member,
4040
Members,
4141
NewProtocol,
42+
Overloaded,
4243
Param,
4344
RaiseError,
4445
Slice,
@@ -169,6 +170,17 @@ def get_annotated_method_hints(cls, *, ctx):
169170
object,
170171
acls,
171172
)
173+
elif isinstance(attr, _apply_generic.WrappedOverloads):
174+
overloads = [
175+
_function_type(_eval_types(of, ctx), receiver_type=acls)
176+
for of in attr.functions
177+
]
178+
hints[name] = (
179+
Overloaded[*overloads],
180+
("ClassVar",),
181+
object,
182+
acls,
183+
)
172184

173185
return hints
174186

typemap/typing.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ def __class_getitem__(cls, params):
101101
return _GenericCallableGenericAlias(cls, (typevars, func))
102102

103103

104+
class Overloaded[*Callables]:
105+
pass
106+
107+
104108
###
105109

106110

0 commit comments

Comments
 (0)