diff --git a/pytype/overlays/functools_overlay.py b/pytype/overlays/functools_overlay.py index fe0924999..687c53787 100644 --- a/pytype/overlays/functools_overlay.py +++ b/pytype/overlays/functools_overlay.py @@ -49,6 +49,10 @@ def __init__(self, ctx: "context.Context", module: str): def new_slot( self, node, cls, func, /, *args, **kwargs ) -> tuple[cfg.CFGNode, cfg.Variable]: + # We are not using ``cls``, because it is set to unsolvable when + # functools.partial is called with *args. + del cls + # Make sure the call is well typed before binding the partial new = self.ctx.convert.convert_pytd_function(self._pytd_new) _, specialized_obj = function.call_function( @@ -56,7 +60,7 @@ def new_slot( node, new.to_variable(node), function.Args( - (cls, func, *args), + (self.to_variable(node), func, *args), kwargs, call_context.starargs, call_context.starstarargs, @@ -65,8 +69,7 @@ def new_slot( ) [specialized_obj] = specialized_obj.data type_arg = specialized_obj.get_formal_type_parameter("_T") - [cls] = cls.data - cls = abstract.ParameterizedClass(cls, {"_T": type_arg}, self.ctx) + cls = abstract.ParameterizedClass(self, {"_T": type_arg}, self.ctx) obj = bind_partial(node, cls, func, args, kwargs, self.ctx) return node, obj.to_variable(node) diff --git a/pytype/tests/test_functions1.py b/pytype/tests/test_functions1.py index dd297ff5c..e96dfbc49 100644 --- a/pytype/tests/test_functions1.py +++ b/pytype/tests/test_functions1.py @@ -1070,6 +1070,20 @@ def f(a, b) -> None: ... """, ) + def test_functools_partial_star(self): + self.Check(""" + from typing import Any + import functools + def f() -> int : + return 42 + def test(*args): + assert_type(functools.partial(*args), functools.partial[Any]) + + # This is WAI in pytype, since *args currently overwrite *all* other + # arguments, including the ones bound positionally prior to *args. + assert_type(functools.partial(f, *args), functools.partial[Any]) + """) + def test_functools_partial_kw(self): self.Check(""" import functools