mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	code_richcompare() now uses the constants types
Issue #25843: When compiling code, don't merge constants if they are equal but have a different types. For example, "f1, f2 = lambda: 1, lambda: 1.0" is now correctly compiled to two different functions: f1() returns 1 (int) and f2() returns 1.0 (int), even if 1 and 1.0 are equal. Add a new _PyCode_ConstantKey() private function.
This commit is contained in:
		
							parent
							
								
									d52513cb22
								
							
						
					
					
						commit
						3cdd5fb970
					
				
					 5 changed files with 245 additions and 49 deletions
				
			
		|  | @ -409,11 +409,135 @@ code_repr(PyCodeObject *co) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| PyObject* | ||||
| _PyCode_ConstantKey(PyObject *op) | ||||
| { | ||||
|     PyObject *key; | ||||
| 
 | ||||
|     /* Py_None and Py_Ellipsis are singleton */ | ||||
|     if (op == Py_None || op == Py_Ellipsis | ||||
|        || PyLong_CheckExact(op) | ||||
|        || PyBool_Check(op) | ||||
|        || PyBytes_CheckExact(op) | ||||
|        || PyUnicode_CheckExact(op) | ||||
|           /* code_richcompare() uses _PyCode_ConstantKey() internally */ | ||||
|        || PyCode_Check(op)) { | ||||
|         key = PyTuple_Pack(2, Py_TYPE(op), op); | ||||
|     } | ||||
|     else if (PyFloat_CheckExact(op)) { | ||||
|         double d = PyFloat_AS_DOUBLE(op); | ||||
|         /* all we need is to make the tuple different in either the 0.0
 | ||||
|          * or -0.0 case from all others, just to avoid the "coercion". | ||||
|          */ | ||||
|         if (d == 0.0 && copysign(1.0, d) < 0.0) | ||||
|             key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None); | ||||
|         else | ||||
|             key = PyTuple_Pack(2, Py_TYPE(op), op); | ||||
|     } | ||||
|     else if (PyComplex_CheckExact(op)) { | ||||
|         Py_complex z; | ||||
|         int real_negzero, imag_negzero; | ||||
|         /* For the complex case we must make complex(x, 0.)
 | ||||
|            different from complex(x, -0.) and complex(0., y) | ||||
|            different from complex(-0., y), for any x and y. | ||||
|            All four complex zeros must be distinguished.*/ | ||||
|         z = PyComplex_AsCComplex(op); | ||||
|         real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0; | ||||
|         imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0; | ||||
|         /* use True, False and None singleton as tags for the real and imag
 | ||||
|          * sign, to make tuples different */ | ||||
|         if (real_negzero && imag_negzero) { | ||||
|             key = PyTuple_Pack(3, Py_TYPE(op), op, Py_True); | ||||
|         } | ||||
|         else if (imag_negzero) { | ||||
|             key = PyTuple_Pack(3, Py_TYPE(op), op, Py_False); | ||||
|         } | ||||
|         else if (real_negzero) { | ||||
|             key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None); | ||||
|         } | ||||
|         else { | ||||
|             key = PyTuple_Pack(2, Py_TYPE(op), op); | ||||
|         } | ||||
|     } | ||||
|     else if (PyTuple_CheckExact(op)) { | ||||
|         Py_ssize_t i, len; | ||||
|         PyObject *tuple; | ||||
| 
 | ||||
|         len = PyTuple_GET_SIZE(op); | ||||
|         tuple = PyTuple_New(len); | ||||
|         if (tuple == NULL) | ||||
|             return NULL; | ||||
| 
 | ||||
|         for (i=0; i < len; i++) { | ||||
|             PyObject *item, *item_key; | ||||
| 
 | ||||
|             item = PyTuple_GET_ITEM(op, i); | ||||
|             item_key = _PyCode_ConstantKey(item); | ||||
|             if (item_key == NULL) { | ||||
|                 Py_DECREF(tuple); | ||||
|                 return NULL; | ||||
|             } | ||||
| 
 | ||||
|             PyTuple_SET_ITEM(tuple, i, item_key); | ||||
|         } | ||||
| 
 | ||||
|         key = PyTuple_Pack(3, Py_TYPE(op), op, tuple); | ||||
|         Py_DECREF(tuple); | ||||
|     } | ||||
|     else if (PyFrozenSet_CheckExact(op)) { | ||||
|         Py_ssize_t pos = 0; | ||||
|         PyObject *item; | ||||
|         Py_hash_t hash; | ||||
|         Py_ssize_t i, len; | ||||
|         PyObject *tuple, *set; | ||||
| 
 | ||||
|         len = PySet_GET_SIZE(op); | ||||
|         tuple = PyTuple_New(len); | ||||
|         if (tuple == NULL) | ||||
|             return NULL; | ||||
| 
 | ||||
|         i = 0; | ||||
|         while (_PySet_NextEntry(op, &pos, &item, &hash)) { | ||||
|             PyObject *item_key; | ||||
| 
 | ||||
|             item_key = _PyCode_ConstantKey(item); | ||||
|             if (item_key == NULL) { | ||||
|                 Py_DECREF(tuple); | ||||
|                 return NULL; | ||||
|             } | ||||
| 
 | ||||
|             assert(i < len); | ||||
|             PyTuple_SET_ITEM(tuple, i, item_key); | ||||
|             i++; | ||||
|         } | ||||
|         set = PyFrozenSet_New(tuple); | ||||
|         Py_DECREF(tuple); | ||||
|         if (set == NULL) | ||||
|             return NULL; | ||||
| 
 | ||||
|         key = PyTuple_Pack(3, Py_TYPE(op), op, set); | ||||
|         Py_DECREF(set); | ||||
|         return key; | ||||
|     } | ||||
|     else { | ||||
|         /* for other types, use the object identifier as an unique identifier
 | ||||
|          * to ensure that they are seen as unequal. */ | ||||
|         PyObject *obj_id = PyLong_FromVoidPtr(op); | ||||
|         if (obj_id == NULL) | ||||
|             return NULL; | ||||
| 
 | ||||
|         key = PyTuple_Pack(3, Py_TYPE(op), op, obj_id); | ||||
|         Py_DECREF(obj_id); | ||||
|     } | ||||
|     return key; | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| code_richcompare(PyObject *self, PyObject *other, int op) | ||||
| { | ||||
|     PyCodeObject *co, *cp; | ||||
|     int eq; | ||||
|     PyObject *consts1, *consts2; | ||||
|     PyObject *res; | ||||
| 
 | ||||
|     if ((op != Py_EQ && op != Py_NE) || | ||||
|  | @ -439,8 +563,21 @@ code_richcompare(PyObject *self, PyObject *other, int op) | |||
|     if (!eq) goto unequal; | ||||
|     eq = PyObject_RichCompareBool(co->co_code, cp->co_code, Py_EQ); | ||||
|     if (eq <= 0) goto unequal; | ||||
|     eq = PyObject_RichCompareBool(co->co_consts, cp->co_consts, Py_EQ); | ||||
| 
 | ||||
|     /* compare constants */ | ||||
|     consts1 = _PyCode_ConstantKey(co->co_consts); | ||||
|     if (!consts1) | ||||
|         return NULL; | ||||
|     consts2 = _PyCode_ConstantKey(cp->co_consts); | ||||
|     if (!consts2) { | ||||
|         Py_DECREF(consts1); | ||||
|         return NULL; | ||||
|     } | ||||
|     eq = PyObject_RichCompareBool(consts1, consts2, Py_EQ); | ||||
|     Py_DECREF(consts1); | ||||
|     Py_DECREF(consts2); | ||||
|     if (eq <= 0) goto unequal; | ||||
| 
 | ||||
|     eq = PyObject_RichCompareBool(co->co_names, cp->co_names, Py_EQ); | ||||
|     if (eq <= 0) goto unequal; | ||||
|     eq = PyObject_RichCompareBool(co->co_varnames, cp->co_varnames, Py_EQ); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner