summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_class.py16
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst3
-rw-r--r--Python/specialize.c5
3 files changed, 24 insertions, 0 deletions
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
index 1531aad..d592714 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -771,6 +771,22 @@ class ClassTests(unittest.TestCase):
with self.assertRaises(RecursionError):
add_one_level()
+ def testMetaclassCallOptimization(self):
+ calls = 0
+
+ class TypeMetaclass(type):
+ def __call__(cls, *args, **kwargs):
+ nonlocal calls
+ calls += 1
+ return type.__call__(cls, *args, **kwargs)
+
+ class Type(metaclass=TypeMetaclass):
+ def __init__(self, obj):
+ self._obj = obj
+
+ for i in range(100):
+ Type(i)
+ self.assertEqual(calls, 100)
if __name__ == '__main__':
unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst
new file mode 100644
index 0000000..795f252
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst
@@ -0,0 +1,3 @@
+No longer specialize calls to classes, if those classes have metaclasses.
+Fixes bug where the ``__call__`` method of the metaclass was not being
+called.
diff --git a/Python/specialize.c b/Python/specialize.c
index a9efbe0..e38e355 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -540,6 +540,7 @@ _PyCode_Quicken(PyCodeObject *code)
#define SPEC_FAIL_CALL_METHOD_WRAPPER 28
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29
#define SPEC_FAIL_CALL_INIT_NOT_SIMPLE 30
+#define SPEC_FAIL_CALL_METACLASS 31
/* COMPARE_OP */
#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
@@ -1757,6 +1758,10 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs)
SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL);
return -1;
}
+ if (Py_TYPE(tp) != &PyType_Type) {
+ SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_METACLASS);
+ return -1;
+ }
if (tp->tp_new == PyBaseObject_Type.tp_new) {
PyFunctionObject *init = get_init_for_simple_managed_python_class(tp);
if (type_get_version(tp, CALL) == 0) {