From 6b28f17a59a7160eeaf73cdc7ffddf979a3083ce Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 23 May 2025 23:18:37 +0000 Subject: [PATCH 1/5] feat: new primitive for weakref.ref --- mypyc/primitives/registry.py | 3 +- mypyc/primitives/weakref_ops.py | 13 +++++++ mypyc/test-data/irbuild-weakref.test | 51 ++++++++++++++++++++++++++++ mypyc/test-data/run-weakref.test | 22 ++++++++++++ mypyc/test/test_irbuild.py | 1 + mypyc/test/test_run.py | 1 + 6 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 mypyc/primitives/weakref_ops.py create mode 100644 mypyc/test-data/irbuild-weakref.test create mode 100644 mypyc/test-data/run-weakref.test diff --git a/mypyc/primitives/registry.py b/mypyc/primitives/registry.py index 5e7ecb70f55d..07546663d08e 100644 --- a/mypyc/primitives/registry.py +++ b/mypyc/primitives/registry.py @@ -371,4 +371,5 @@ def load_address_op(name: str, type: RType, src: str) -> LoadAddressDescription: import mypyc.primitives.list_ops import mypyc.primitives.misc_ops import mypyc.primitives.str_ops -import mypyc.primitives.tuple_ops # noqa: F401 +import mypyc.primitives.tuple_ops +import mypyc.primitives.weakref_ops # noqa: F401 diff --git a/mypyc/primitives/weakref_ops.py b/mypyc/primitives/weakref_ops.py new file mode 100644 index 000000000000..19f8bc858732 --- /dev/null +++ b/mypyc/primitives/weakref_ops.py @@ -0,0 +1,13 @@ +from mypyc.ir.ops import ERR_MAGIC +from mypyc.ir.rtypes import object_rprimitive +from mypyc.primitives.registry import function_op + +# Weakref operations + +new_ref_op = function_op( + name="weakref.ReferenceType", + arg_types=[object_rprimitive, object_rprimitive], + return_type=object_rprimitive, + c_function_name="PyWeakref_NewRef", + error_kind=ERR_MAGIC, +) diff --git a/mypyc/test-data/irbuild-weakref.test b/mypyc/test-data/irbuild-weakref.test new file mode 100644 index 000000000000..29894916bd7a --- /dev/null +++ b/mypyc/test-data/irbuild-weakref.test @@ -0,0 +1,51 @@ +[case testWeakrefRef] +import weakref +from typing import Any, Callable +def f(x: object) -> object: + return weakref.ref(x) + +[out] +def f(x): + x, r0 :: object +L0: + r0 = PyWeakref_NewRef(x, NULL) + return r0 + +[case testWeakrefRefCallback] +import weakref +from typing import Any, Callable +def f(x: object, cb: Callable[[object], Any]) -> object: + return weakref.ref(x, cb) + +[out] +def f(x, cb): + x, cb, r0 :: object +L0: + r0 = PyWeakref_NewRef(x, cb) + return r0 + +[case testFromWeakrefRef] +from typing import Any, Callable +from weakref import ref +def f(x: object) -> object: + return ref(x) + +[out] +def f(x): + x, r0 :: object +L0: + r0 = PyWeakref_NewRef(x, NULL) + return r0 + +[case testFromWeakrefRefCallback] +from typing import Any, Callable +from weakref import ref +def f(x: object, cb: Callable[[object], Any]) -> object: + return ref(x, cb) + +[out] +def f(x, cb): + x, cb, r0 :: object +L0: + r0 = PyWeakref_NewRef(x, cb) + return r0 diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test new file mode 100644 index 000000000000..c7c85c7a4cc8 --- /dev/null +++ b/mypyc/test-data/run-weakref.test @@ -0,0 +1,22 @@ +# Test cases for weakrefs (compile and run) + +[case testWeakrefRef] +import asyncio +import pytest # type: ignore [import-not-found] +from weakref import ref + +def test_weakref_ref(): + # some random weakreffable object + obj = asyncio.new_event_loop() + r = ref(obj) + assert r() is obj + obj = None + assert r() is None, r() + +def test_weakref_ref_with_callback(): + # some random weakreffable object + obj = asyncio.new_event_loop() + r = ref(obj, lambda x: x) + assert r() is obj + obj = None + assert r() is None, r() diff --git a/mypyc/test/test_irbuild.py b/mypyc/test/test_irbuild.py index 9c0ad06416a7..d8f974ef201b 100644 --- a/mypyc/test/test_irbuild.py +++ b/mypyc/test/test_irbuild.py @@ -53,6 +53,7 @@ "irbuild-constant-fold.test", "irbuild-glue-methods.test", "irbuild-math.test", + "irbuild-weakref.test", ] if sys.version_info >= (3, 10): diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index e5b7e2421433..cd32daee4bdc 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -69,6 +69,7 @@ "run-dunders-special.test", "run-singledispatch.test", "run-attrs.test", + "run-weakref.test", "run-python37.test", "run-python38.test", ] From 8d41c269b345c651d76a56f10bd213f648662e44 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 23 May 2025 23:38:58 +0000 Subject: [PATCH 2/5] fix(test): fix test ref --- mypyc/test-data/run-weakref.test | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index c7c85c7a4cc8..dd8a606e8ef2 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -5,17 +5,20 @@ import asyncio import pytest # type: ignore [import-not-found] from weakref import ref +@mypyc_attr(native_class=False) +class Object: + """some random weakreffable object""" + pass + def test_weakref_ref(): - # some random weakreffable object - obj = asyncio.new_event_loop() + obj = Object() r = ref(obj) assert r() is obj obj = None assert r() is None, r() def test_weakref_ref_with_callback(): - # some random weakreffable object - obj = asyncio.new_event_loop() + obj = Object() r = ref(obj, lambda x: x) assert r() is obj obj = None From 97f9186a8a6ef7d7d1ac22fcfbd171191d04de8b Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 23 May 2025 23:40:42 +0000 Subject: [PATCH 3/5] fix(test): only test with callback --- mypyc/test-data/irbuild-weakref.test | 26 -------------------------- mypyc/test-data/run-weakref.test | 7 ------- 2 files changed, 33 deletions(-) diff --git a/mypyc/test-data/irbuild-weakref.test b/mypyc/test-data/irbuild-weakref.test index 29894916bd7a..2258d06115be 100644 --- a/mypyc/test-data/irbuild-weakref.test +++ b/mypyc/test-data/irbuild-weakref.test @@ -1,16 +1,3 @@ -[case testWeakrefRef] -import weakref -from typing import Any, Callable -def f(x: object) -> object: - return weakref.ref(x) - -[out] -def f(x): - x, r0 :: object -L0: - r0 = PyWeakref_NewRef(x, NULL) - return r0 - [case testWeakrefRefCallback] import weakref from typing import Any, Callable @@ -24,19 +11,6 @@ L0: r0 = PyWeakref_NewRef(x, cb) return r0 -[case testFromWeakrefRef] -from typing import Any, Callable -from weakref import ref -def f(x: object) -> object: - return ref(x) - -[out] -def f(x): - x, r0 :: object -L0: - r0 = PyWeakref_NewRef(x, NULL) - return r0 - [case testFromWeakrefRefCallback] from typing import Any, Callable from weakref import ref diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index dd8a606e8ef2..f23141ab0c9a 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -10,13 +10,6 @@ class Object: """some random weakreffable object""" pass -def test_weakref_ref(): - obj = Object() - r = ref(obj) - assert r() is obj - obj = None - assert r() is None, r() - def test_weakref_ref_with_callback(): obj = Object() r = ref(obj, lambda x: x) From 81eadfbf907233cb5c1b6c24c9b5f7c1ce0b8fa6 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 23 May 2025 19:48:37 -0400 Subject: [PATCH 4/5] Update run-weakref.test --- mypyc/test-data/run-weakref.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mypyc/test-data/run-weakref.test b/mypyc/test-data/run-weakref.test index f23141ab0c9a..de2d5dd5bad2 100644 --- a/mypyc/test-data/run-weakref.test +++ b/mypyc/test-data/run-weakref.test @@ -4,6 +4,7 @@ import asyncio import pytest # type: ignore [import-not-found] from weakref import ref +from mypy_extensions import mypyc_attr @mypyc_attr(native_class=False) class Object: From 3b71a7f71d1ede3ff858285c68d9cce43fa02ed0 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 23 May 2025 23:58:42 +0000 Subject: [PATCH 5/5] feat: new primitive for `weakref.__call__` --- mypyc/primitives/weakref_ops.py | 10 +++++++++- mypyc/test-data/irbuild-weakref.test | 14 ++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/mypyc/primitives/weakref_ops.py b/mypyc/primitives/weakref_ops.py index 19f8bc858732..024f9fedd17f 100644 --- a/mypyc/primitives/weakref_ops.py +++ b/mypyc/primitives/weakref_ops.py @@ -1,6 +1,6 @@ from mypyc.ir.ops import ERR_MAGIC from mypyc.ir.rtypes import object_rprimitive -from mypyc.primitives.registry import function_op +from mypyc.primitives.registry import ERR_NEG_INT, function_op # Weakref operations @@ -11,3 +11,11 @@ c_function_name="PyWeakref_NewRef", error_kind=ERR_MAGIC, ) + +deref_op = function_op( + name="weakref.ReferenceType.__call__", + arg_types=[object_rprimitive], + return_type=object_rprimitive, + c_function_name="PyWeakref_GetRef", + error_kind=ERR_NEG_INT, +) diff --git a/mypyc/test-data/irbuild-weakref.test b/mypyc/test-data/irbuild-weakref.test index 2258d06115be..1b8c894821e5 100644 --- a/mypyc/test-data/irbuild-weakref.test +++ b/mypyc/test-data/irbuild-weakref.test @@ -2,24 +2,26 @@ import weakref from typing import Any, Callable def f(x: object, cb: Callable[[object], Any]) -> object: - return weakref.ref(x, cb) + return weakref.ref(x, cb)() [out] def f(x, cb): - x, cb, r0 :: object + x, cb, r0, r1 :: object L0: r0 = PyWeakref_NewRef(x, cb) - return r0 + r1 = PyWeakref_GetRef(r0) + return r1 [case testFromWeakrefRefCallback] from typing import Any, Callable from weakref import ref def f(x: object, cb: Callable[[object], Any]) -> object: - return ref(x, cb) + return ref(x, cb)() [out] def f(x, cb): - x, cb, r0 :: object + x, cb, r0, r1 :: object L0: r0 = PyWeakref_NewRef(x, cb) - return r0 + r1 = PyWeakref_GetRef(r0) + return r1