diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 30444b7d6774247..36e3318d320cee5 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1061,16 +1061,33 @@ static PyMappingMethods mappingproxy_as_mapping = { 0, /* mp_ass_subscript */ }; +static int mappingproxy_is_known_dict_subclass_or(PyObject *o) { + return (PyAnyDict_CheckExact(o) || PyODict_CheckExact(o) || + (PyAnyDict_Check(o) && Py_TYPE(o)->tp_as_number->nb_or == PyDict_Type.tp_as_number->nb_or)) || + (PyODict_Check(o) && Py_TYPE(o)->tp_as_number->nb_or == PyODict_Type.tp_as_number->nb_or); +} + static PyObject * mappingproxy_or(PyObject *left, PyObject *right) { if (PyObject_TypeCheck(left, &PyDictProxy_Type)) { - left = ((mappingproxyobject*)left)->mapping; - } - if (PyObject_TypeCheck(right, &PyDictProxy_Type)) { - right = ((mappingproxyobject*)right)->mapping; + if (PyObject_TypeCheck(right, &PyDictProxy_Type)) { + right = ((mappingproxyobject*)right)->mapping; + } + PyObject *left_mapping = ((mappingproxyobject*)left)->mapping; + if (mappingproxy_is_known_dict_subclass_or(right) || PyFrozenDict_CheckExact(left_mapping)) { + return PyNumber_Or(left_mapping, right); + } + } else { + assert(PyObject_TypeCheck(right, &PyDictProxy_Type)); + PyObject *right_mapping = ((mappingproxyobject*)right)->mapping; + if (mappingproxy_is_known_dict_subclass_or(left) || PyFrozenDict_CheckExact(right_mapping)) { + return PyNumber_Or(left, right_mapping); + } } - return PyNumber_Or(left, right); + + // The non-mappingproxy "or" will have to deal with a mappingproxy. + Py_RETURN_NOTIMPLEMENTED; } static PyObject * @@ -1229,14 +1246,26 @@ mappingproxy_traverse(PyObject *self, visitproc visit, void *arg) return 0; } +static int +mappingproxy_is_known_dict_subclass_richcompare(PyObject *o) { + return (PyAnyDict_CheckExact(o) || PyODict_CheckExact(o) || + (PyAnyDict_Check(o) && Py_TYPE(o)->tp_richcompare == PyDict_Type.tp_richcompare) || + (PyODict_Check(o) && Py_TYPE(o)->tp_richcompare == PyODict_Type.tp_richcompare)); +} + static PyObject * mappingproxy_richcompare(PyObject *self, PyObject *w, int op) { - mappingproxyobject *v = (mappingproxyobject *)self; if (op == Py_EQ || op == Py_NE) { - return PyObject_RichCompare(v->mapping, w, op); + mappingproxyobject *v = (mappingproxyobject *)self; + if (PyObject_TypeCheck(w, &PyDictProxy_Type)) { + w = ((mappingproxyobject *)w)->mapping; + } + if (mappingproxy_is_known_dict_subclass_richcompare(w) || PyFrozenDict_CheckExact(v->mapping)) { + return PyObject_RichCompare(v->mapping, w, op); + } } - Py_RETURN_NOTIMPLEMENTED; + Py_RETURN_NOTIMPLEMENTED; // Defer to w's richcompare } static int