@@ -1967,3 +1967,69 @@ class Info(typing.TypedDict):
19671967
19681968 subs = unify (collections .abc .Mapping , Info )
19691969 assert subs == {}
1970+
1971+
1972+ def test_unify_jax_array_iterable ():
1973+ import jax
1974+
1975+ subs = unify (collections .abc .Iterable [T ], jax .Array )
1976+ assert subs == {T : jax .Array }
1977+
1978+
1979+ def test_unify_operation_callable ():
1980+ """An ``Operation[P, R]`` unifies as a ``Callable[P, R]`` (gh #669)."""
1981+ from effectful .ops .types import Operation
1982+
1983+ # TypeVar params bind to the operation's parameter/return types
1984+ assert unify (collections .abc .Callable [[T ], V ], Operation [[int ], int ]) == {
1985+ T : int ,
1986+ V : int ,
1987+ }
1988+ # a repeated TypeVar binds consistently
1989+ assert unify (collections .abc .Callable [[T ], T ], Operation [[int ], int ]) == {T : int }
1990+ # multiple parameters
1991+ assert unify (collections .abc .Callable [[T , U ], V ], Operation [[int , str ], bool ]) == {
1992+ T : int ,
1993+ U : str ,
1994+ V : bool ,
1995+ }
1996+ # ``...`` parameters in the pattern ignore the operation's parameter types
1997+ assert unify (collections .abc .Callable [..., V ], Operation [[int ], int ]) == {V : int }
1998+ # fully concrete: nothing to bind
1999+ assert unify (collections .abc .Callable [[int ], int ], Operation [[int ], int ]) == {}
2000+ # nested: an operation-valued argument
2001+ assert unify (
2002+ collections .abc .Callable [[T ], list [V ]], Operation [[int ], list [str ]]
2003+ ) == {T : int , V : str }
2004+
2005+
2006+ def test_unify_operation_callable_failure ():
2007+ """An arity mismatch between the Callable pattern and the Operation fails."""
2008+ from effectful .ops .types import Operation
2009+
2010+ with pytest .raises (TypeError ):
2011+ unify (collections .abc .Callable [[T , U ], V ], Operation [[int ], int ])
2012+ with pytest .raises (TypeError ):
2013+ unify (collections .abc .Callable [[T ], V ], Operation [[int , str ], bool ])
2014+
2015+
2016+ def test_operation_unifies_with_callable_param_gh669 ():
2017+ """An Operation passed where a ``Callable`` is expected infers correctly.
2018+
2019+ Regression test for gh #669: calling an operation whose parameter is typed
2020+ ``Callable[[S], T]`` with another operation should unify and infer the return
2021+ type, rather than raising ``Cannot unify generic type ...``.
2022+ """
2023+ from effectful .ops .semantics import typeof
2024+ from effectful .ops .types import NotHandled , Operation
2025+
2026+ @Operation .define
2027+ def f (x : int ) -> int :
2028+ raise NotHandled
2029+
2030+ @Operation .define
2031+ def g [S , R ](x : collections .abc .Callable [[S ], R ]) -> R :
2032+ raise NotHandled
2033+
2034+ term = g (f )
2035+ assert typeof (term ) is int
0 commit comments