@@ -332,7 +332,7 @@ compiler_set_qualname(compiler *c)
332332}
333333
334334/* Merge const *o* and return constant key object.
335- * If recursive, insert all elements if o is a tuple or frozen set .
335+ * If recursive, insert all elements if o is a tuple, frozenset, or frozendict .
336336 */
337337static PyObject *
338338const_cache_insert (PyObject * const_cache , PyObject * o , bool recursive )
@@ -364,7 +364,7 @@ const_cache_insert(PyObject *const_cache, PyObject *o, bool recursive)
364364 }
365365
366366 // We registered o in const_cache.
367- // When o is a tuple or frozenset , we want to merge its
367+ // When o is a tuple, frozenset, or frozendict , we want to merge its
368368 // items too.
369369 if (PyTuple_CheckExact (o )) {
370370 Py_ssize_t len = PyTuple_GET_SIZE (o );
@@ -431,7 +431,7 @@ const_cache_insert(PyObject *const_cache, PyObject *o, bool recursive)
431431 }
432432
433433 // Instead of rewriting o, we create new frozenset and embed in the
434- // key tuple. Caller should get merged frozenset from the key tuple.
434+ // key tuple. Caller should get merged frozenset from the key tuple.
435435 PyObject * new = PyFrozenSet_New (tuple );
436436 Py_DECREF (tuple );
437437 if (new == NULL ) {
@@ -442,6 +442,77 @@ const_cache_insert(PyObject *const_cache, PyObject *o, bool recursive)
442442 Py_DECREF (o );
443443 PyTuple_SET_ITEM (key , 1 , new );
444444 }
445+ else if (PyFrozenDict_CheckExact (o )) {
446+ // *key* is tuple. And its first item is frozendict of
447+ // constant keys.
448+ // See _PyCode_ConstantKey() for detail.
449+ assert (PyTuple_CheckExact (key ));
450+ assert (PyTuple_GET_SIZE (key ) == 2 );
451+
452+ if (PyDict_GET_SIZE (o ) == 0 ) { // empty frozendict should not be re-created.
453+ return key ;
454+ }
455+ PyObject * new_dict = PyDict_New ();
456+ if (new_dict == NULL ) {
457+ Py_DECREF (key );
458+ return NULL ;
459+ }
460+ Py_ssize_t pos = 0 ;
461+ PyObject * k_obj , * v_obj ;
462+ while (PyDict_Next (o , & pos , & k_obj , & v_obj )) {
463+ PyObject * k_result = const_cache_insert (const_cache , k_obj , recursive );
464+ if (k_result == NULL ) {
465+ Py_DECREF (new_dict );
466+ Py_DECREF (key );
467+ return NULL ;
468+ }
469+ PyObject * k_merged ;
470+ if (PyTuple_CheckExact (k_result )) {
471+ k_merged = Py_NewRef (PyTuple_GET_ITEM (k_result , 1 ));
472+ Py_DECREF (k_result );
473+ }
474+ else {
475+ k_merged = k_result ;
476+ }
477+
478+ PyObject * v_result = const_cache_insert (const_cache , v_obj , recursive );
479+ if (v_result == NULL ) {
480+ Py_DECREF (k_merged );
481+ Py_DECREF (new_dict );
482+ Py_DECREF (key );
483+ return NULL ;
484+ }
485+ PyObject * v_merged ;
486+ if (PyTuple_CheckExact (v_result )) {
487+ v_merged = Py_NewRef (PyTuple_GET_ITEM (v_result , 1 ));
488+ Py_DECREF (v_result );
489+ }
490+ else {
491+ v_merged = v_result ;
492+ }
493+
494+ int res = PyDict_SetItem (new_dict , k_merged , v_merged );
495+ Py_DECREF (k_merged );
496+ Py_DECREF (v_merged );
497+ if (res < 0 ) {
498+ Py_DECREF (new_dict );
499+ Py_DECREF (key );
500+ return NULL ;
501+ }
502+ }
503+
504+ // Instead of rewriting o, we create new frozendict and embed in
505+ // the key tuple. Caller should get merged frozendict from the key tuple.
506+ PyObject * new = PyFrozenDict_New (new_dict );
507+ Py_DECREF (new_dict );
508+ if (new == NULL ) {
509+ Py_DECREF (key );
510+ return NULL ;
511+ }
512+ assert (PyTuple_GET_ITEM (key , 1 ) == o );
513+ Py_DECREF (o );
514+ PyTuple_SET_ITEM (key , 1 , new );
515+ }
445516
446517 return key ;
447518}
0 commit comments