@@ -409,11 +409,135 @@ code_repr(PyCodeObject *co)
409409 }
410410}
411411
412+ PyObject *
413+ _PyCode_ConstantKey (PyObject * op )
414+ {
415+ PyObject * key ;
416+
417+ /* Py_None and Py_Ellipsis are singleton */
418+ if (op == Py_None || op == Py_Ellipsis
419+ || PyLong_CheckExact (op )
420+ || PyBool_Check (op )
421+ || PyBytes_CheckExact (op )
422+ || PyUnicode_CheckExact (op )
423+ /* code_richcompare() uses _PyCode_ConstantKey() internally */
424+ || PyCode_Check (op )) {
425+ key = PyTuple_Pack (2 , Py_TYPE (op ), op );
426+ }
427+ else if (PyFloat_CheckExact (op )) {
428+ double d = PyFloat_AS_DOUBLE (op );
429+ /* all we need is to make the tuple different in either the 0.0
430+ * or -0.0 case from all others, just to avoid the "coercion".
431+ */
432+ if (d == 0.0 && copysign (1.0 , d ) < 0.0 )
433+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , Py_None );
434+ else
435+ key = PyTuple_Pack (2 , Py_TYPE (op ), op );
436+ }
437+ else if (PyComplex_CheckExact (op )) {
438+ Py_complex z ;
439+ int real_negzero , imag_negzero ;
440+ /* For the complex case we must make complex(x, 0.)
441+ different from complex(x, -0.) and complex(0., y)
442+ different from complex(-0., y), for any x and y.
443+ All four complex zeros must be distinguished.*/
444+ z = PyComplex_AsCComplex (op );
445+ real_negzero = z .real == 0.0 && copysign (1.0 , z .real ) < 0.0 ;
446+ imag_negzero = z .imag == 0.0 && copysign (1.0 , z .imag ) < 0.0 ;
447+ /* use True, False and None singleton as tags for the real and imag
448+ * sign, to make tuples different */
449+ if (real_negzero && imag_negzero ) {
450+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , Py_True );
451+ }
452+ else if (imag_negzero ) {
453+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , Py_False );
454+ }
455+ else if (real_negzero ) {
456+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , Py_None );
457+ }
458+ else {
459+ key = PyTuple_Pack (2 , Py_TYPE (op ), op );
460+ }
461+ }
462+ else if (PyTuple_CheckExact (op )) {
463+ Py_ssize_t i , len ;
464+ PyObject * tuple ;
465+
466+ len = PyTuple_GET_SIZE (op );
467+ tuple = PyTuple_New (len );
468+ if (tuple == NULL )
469+ return NULL ;
470+
471+ for (i = 0 ; i < len ; i ++ ) {
472+ PyObject * item , * item_key ;
473+
474+ item = PyTuple_GET_ITEM (op , i );
475+ item_key = _PyCode_ConstantKey (item );
476+ if (item_key == NULL ) {
477+ Py_DECREF (tuple );
478+ return NULL ;
479+ }
480+
481+ PyTuple_SET_ITEM (tuple , i , item_key );
482+ }
483+
484+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , tuple );
485+ Py_DECREF (tuple );
486+ }
487+ else if (PyFrozenSet_CheckExact (op )) {
488+ Py_ssize_t pos = 0 ;
489+ PyObject * item ;
490+ Py_hash_t hash ;
491+ Py_ssize_t i , len ;
492+ PyObject * tuple , * set ;
493+
494+ len = PySet_GET_SIZE (op );
495+ tuple = PyTuple_New (len );
496+ if (tuple == NULL )
497+ return NULL ;
498+
499+ i = 0 ;
500+ while (_PySet_NextEntry (op , & pos , & item , & hash )) {
501+ PyObject * item_key ;
502+
503+ item_key = _PyCode_ConstantKey (item );
504+ if (item_key == NULL ) {
505+ Py_DECREF (tuple );
506+ return NULL ;
507+ }
508+
509+ assert (i < len );
510+ PyTuple_SET_ITEM (tuple , i , item_key );
511+ i ++ ;
512+ }
513+ set = PyFrozenSet_New (tuple );
514+ Py_DECREF (tuple );
515+ if (set == NULL )
516+ return NULL ;
517+
518+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , set );
519+ Py_DECREF (set );
520+ return key ;
521+ }
522+ else {
523+ /* for other types, use the object identifier as an unique identifier
524+ * to ensure that they are seen as unequal. */
525+ PyObject * obj_id = PyLong_FromVoidPtr (op );
526+ if (obj_id == NULL )
527+ return NULL ;
528+
529+ key = PyTuple_Pack (3 , Py_TYPE (op ), op , obj_id );
530+ Py_DECREF (obj_id );
531+ }
532+ return key ;
533+ }
534+
412535static PyObject *
413536code_richcompare (PyObject * self , PyObject * other , int op )
414537{
415538 PyCodeObject * co , * cp ;
416539 int eq ;
540+ PyObject * consts1 , * consts2 ;
417541 PyObject * res ;
418542
419543 if ((op != Py_EQ && op != Py_NE ) ||
@@ -439,8 +563,21 @@ code_richcompare(PyObject *self, PyObject *other, int op)
439563 if (!eq ) goto unequal ;
440564 eq = PyObject_RichCompareBool (co -> co_code , cp -> co_code , Py_EQ );
441565 if (eq <= 0 ) goto unequal ;
442- eq = PyObject_RichCompareBool (co -> co_consts , cp -> co_consts , Py_EQ );
566+
567+ /* compare constants */
568+ consts1 = _PyCode_ConstantKey (co -> co_consts );
569+ if (!consts1 )
570+ return NULL ;
571+ consts2 = _PyCode_ConstantKey (cp -> co_consts );
572+ if (!consts2 ) {
573+ Py_DECREF (consts1 );
574+ return NULL ;
575+ }
576+ eq = PyObject_RichCompareBool (consts1 , consts2 , Py_EQ );
577+ Py_DECREF (consts1 );
578+ Py_DECREF (consts2 );
443579 if (eq <= 0 ) goto unequal ;
580+
444581 eq = PyObject_RichCompareBool (co -> co_names , cp -> co_names , Py_EQ );
445582 if (eq <= 0 ) goto unequal ;
446583 eq = PyObject_RichCompareBool (co -> co_varnames , cp -> co_varnames , Py_EQ );
0 commit comments