@@ -1208,14 +1208,18 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
12081208 // t is borrowed reference
12091209 PyObject * t = PyDict_SetDefault (c -> c_const_cache , key , key );
12101210 if (t != key ) {
1211+ // o is registered in c_const_cache. Just use it.
12111212 Py_INCREF (t );
12121213 Py_DECREF (key );
12131214 return t ;
12141215 }
12151216
1217+ // We registered o in c_const_cache.
1218+ // When o is a tuple or frozenset, we want to merge it's
1219+ // items too.
12161220 if (PyTuple_CheckExact (o )) {
1217- Py_ssize_t i , len = PyTuple_GET_SIZE (o );
1218- for (i = 0 ; i < len ; i ++ ) {
1221+ Py_ssize_t len = PyTuple_GET_SIZE (o );
1222+ for (Py_ssize_t i = 0 ; i < len ; i ++ ) {
12191223 PyObject * item = PyTuple_GET_ITEM (o , i );
12201224 PyObject * u = merge_consts_recursive (c , item );
12211225 if (u == NULL ) {
@@ -1240,6 +1244,57 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
12401244 Py_DECREF (u );
12411245 }
12421246 }
1247+ else if (PyFrozenSet_CheckExact (o )) {
1248+ // *key* is tuple. And it's first item is frozenset of
1249+ // constant keys.
1250+ // See _PyCode_ConstantKey() for detail.
1251+ assert (PyTuple_CheckExact (key ));
1252+ assert (PyTuple_GET_SIZE (key ) == 2 );
1253+
1254+ Py_ssize_t len = PySet_GET_SIZE (o );
1255+ if (len == 0 ) { // empty frozenset should not be re-created.
1256+ return key ;
1257+ }
1258+ PyObject * tuple = PyTuple_New (len );
1259+ if (tuple == NULL ) {
1260+ Py_DECREF (key );
1261+ return NULL ;
1262+ }
1263+ Py_ssize_t i = 0 , pos = 0 ;
1264+ PyObject * item ;
1265+ Py_hash_t hash ;
1266+ while (_PySet_NextEntry (o , & pos , & item , & hash )) {
1267+ PyObject * k = merge_consts_recursive (c , item );
1268+ if (k == NULL ) {
1269+ Py_DECREF (tuple );
1270+ Py_DECREF (key );
1271+ return NULL ;
1272+ }
1273+ PyObject * u ;
1274+ if (PyTuple_CheckExact (k )) {
1275+ u = PyTuple_GET_ITEM (k , 1 );
1276+ Py_INCREF (u );
1277+ Py_DECREF (k );
1278+ }
1279+ else {
1280+ u = k ;
1281+ }
1282+ PyTuple_SET_ITEM (tuple , i , u ); // Steals reference of u.
1283+ i ++ ;
1284+ }
1285+
1286+ // Instead of rewriting o, we create new frozenset and embed in the
1287+ // key tuple. Caller should get merged frozenset from the key tuple.
1288+ PyObject * new = PyFrozenSet_New (tuple );
1289+ Py_DECREF (tuple );
1290+ if (new == NULL ) {
1291+ Py_DECREF (key );
1292+ return NULL ;
1293+ }
1294+ assert (PyTuple_GET_ITEM (key , 1 ) == o );
1295+ Py_DECREF (o );
1296+ PyTuple_SET_ITEM (key , 1 , new );
1297+ }
12431298
12441299 return key ;
12451300}
0 commit comments