| from __future__ import annotations | |
| import unittest | |
| from mypyc.analysis.attrdefined import detect_undefined_bitmap | |
| from mypyc.codegen.emit import Emitter, EmitterContext | |
| from mypyc.codegen.emitclass import ( | |
| generate_getter, | |
| generate_setter, | |
| getter_name, | |
| setter_name, | |
| slot_key, | |
| ) | |
| from mypyc.common import IS_FREE_THREADED | |
| from mypyc.ir.class_ir import ClassIR | |
| from mypyc.ir.rtypes import int32_rprimitive, object_rprimitive | |
| from mypyc.namegen import NameGenerator | |
| class TestEmitClass(unittest.TestCase): | |
| def test_slot_key(self) -> None: | |
| attrs = ["__add__", "__radd__", "__rshift__", "__rrshift__", "__setitem__", "__delitem__"] | |
| s = sorted(attrs, key=lambda x: slot_key(x)) | |
| # __delitem__ and reverse methods should come last. | |
| assert s == [ | |
| "__add__", | |
| "__rshift__", | |
| "__setitem__", | |
| "__delitem__", | |
| "__radd__", | |
| "__rrshift__", | |
| ] | |
| def test_setter_name(self) -> None: | |
| cls = ClassIR(module_name="testing", name="SomeClass") | |
| generator = NameGenerator([["mod"]]) | |
| # This should never be `setup`, as it will conflict with the class `setup` | |
| assert setter_name(cls, "up", generator) == "testing___SomeClass_set_up" | |
| def test_getter_name(self) -> None: | |
| cls = ClassIR(module_name="testing", name="SomeClass") | |
| generator = NameGenerator([["mod"]]) | |
| assert getter_name(cls, "down", generator) == "testing___SomeClass_get_down" | |
| @unittest.skipUnless(IS_FREE_THREADED, "requires a free threaded build") | |
| def test_free_threaded_ref_attribute_getter_and_setter_use_owner(self) -> None: | |
| # Note: We can't monkey patch IS_FREE_THREADED to test this on a build with | |
| # the GIL enabled, since monkey patching doesn't work if mypyc is compiled. | |
| cl = ClassIR("A", "mod") | |
| cl.attributes = {"o": object_rprimitive} | |
| cl.deletable = ["o"] | |
| cl.mro = cl.base_mro = [cl] | |
| emitter = Emitter(EmitterContext(NameGenerator([["mod"]]), True)) | |
| generate_getter(cl, "o", object_rprimitive, emitter) | |
| generate_setter(cl, "o", object_rprimitive, emitter) | |
| generated = "".join(emitter.fragments) | |
| assert "CPy_GetAttrRef((PyObject *)self, (PyObject **)&self->_o)" in generated | |
| assert "CPy_SetAttrRef((PyObject *)self, (PyObject **)&self->_o, tmp)" in generated | |
| assert "CPy_SetAttrRef((PyObject *)self, (PyObject **)&self->_o, NULL)" in generated | |
| def test_bitmap_attrs_stable_across_repeat_analysis(self) -> None: | |
| # Regression: detect_undefined_bitmap used to mutate cl.bitmap_attrs | |
| # in place, so under separate=True (one SCC per group) a shared base | |
| # class would accumulate duplicate entries as each subclass's SCC | |
| # walked into it, growing the emitted struct between builds. | |
| base = ClassIR("Base", "mod") | |
| base.attributes = {"i": int32_rprimitive} | |
| sub = ClassIR("Sub", "mod") | |
| sub.attributes = {"j": int32_rprimitive} | |
| base.mro = base.base_mro = [base] | |
| sub.mro = sub.base_mro = [sub, base] | |
| base.children = [sub] | |
| detect_undefined_bitmap(sub, seen=set()) | |
| for _ in range(10): | |
| detect_undefined_bitmap(sub, seen=set()) | |
| assert base.bitmap_attrs == ["i"] | |
| assert sub.bitmap_attrs == ["i", "j"] |