@@ -1208,14 +1208,18 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
1208
1208
// t is borrowed reference
1209
1209
PyObject * t = PyDict_SetDefault (c -> c_const_cache , key , key );
1210
1210
if (t != key ) {
1211
+ // o is registered in c_const_cache. Just use it.
1211
1212
Py_INCREF (t);
1212
1213
Py_DECREF (key );
1213
1214
return t ;
1214
1215
}
1215
1216
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.
1216
1220
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 ++ ) {
1219
1223
PyObject * item = PyTuple_GET_ITEM (o , i );
1220
1224
PyObject * u = merge_consts_recursive (c , item );
1221
1225
if (u == NULL ) {
@@ -1240,6 +1244,57 @@ merge_consts_recursive(struct compiler *c, PyObject *o)
1240
1244
Py_DECREF (u );
1241
1245
}
1242
1246
}
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
+ }
1243
1298
1244
1299
return key ;
1245
1300
}
0 commit comments