From 182dc6d1be320d13871e4b767e85233c6c5668cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Fri, 16 Aug 2024 22:05:56 +0300 Subject: [PATCH 1/8] Implement desired functionality --- Python/ast_opt.c | 63 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index d7a26e64150e55..d41e8c51b51814 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -624,8 +624,11 @@ static int fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) { asdl_int_seq *ops; - asdl_expr_seq *args; + asdl_expr_seq *args, *elts; + expr_ty arg; + PyObject *lhs_const; Py_ssize_t i; + Py_ssize_t elts_len; ops = node->v.Compare.ops; args = node->v.Compare.comparators; @@ -633,11 +636,65 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) tuple or frozenset respectively. */ i = asdl_seq_LEN(ops) - 1; int op = asdl_seq_GET(ops, i); + arg = asdl_seq_GET(args, i); + if ((node->v.Compare.left->kind) != Constant_kind) + return 1; + lhs_const = node->v.Compare.left->v.Constant.value; if (op == In || op == NotIn) { - if (!fold_iter((expr_ty)asdl_seq_GET(args, i), arena, state)) { - return 0; + if (arg->kind == List_kind) { + asdl_expr_seq *list_elts = arg->v.List.elts; + if (has_starred(list_elts)) + return 1; + elts = list_elts; + } + else if (arg->kind == Dict_kind) { + elts = arg->v.Dict.keys; + } + else if (arg->kind == Set_kind) { + elts = arg->v.Set.elts; + } + else { + return 1; + } + elts_len = asdl_seq_LEN(elts); + if (!elts_len) { + return make_const(node, op == In ? Py_False : Py_True, arena); + } + PyObject *newtuple = PyTuple_New(elts_len); + if (newtuple == NULL) { + if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { + return 0; + } + PyErr_Clear(); + return 1; + } + for (Py_ssize_t j = 0; j < elts_len; j++) { + expr_ty e = (expr_ty)asdl_seq_GET(elts, j); + if (e->kind != Constant_kind) { + PyObject_GC_UnTrack(newtuple); + PyObject_GC_Del(newtuple); + return 0; + } + PyObject *v = e->v.Constant.value; + PyTuple_SET_ITEM(newtuple, j, Py_NewRef(v)); + if (v == lhs_const && op == In) { + PyObject_GC_UnTrack(newtuple); + PyObject_GC_Del(newtuple); + return make_const(node, Py_True, arena); + } + } + if (op == NotIn) { + PyObject_GC_UnTrack(newtuple); + PyObject_GC_Del(newtuple); + return make_const(node, Py_True, arena); } + return make_const(arg, newtuple, arena); } + else if ((op == Eq || op == NotEq) && arg->kind == Constant_kind) { + if (lhs_const == arg->v.Constant.value) + return make_const(node, op == Eq ? Py_True : Py_False, arena); + } + return 1; } From d4a97b0dcf2be39736b39b24dee601c5c56ca2b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Sun, 18 Aug 2024 16:22:28 +0300 Subject: [PATCH 2/8] Necessary fixes --- Python/ast_opt.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index d41e8c51b51814..cc4c9f3afa6aba 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -626,7 +626,6 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) asdl_int_seq *ops; asdl_expr_seq *args, *elts; expr_ty arg; - PyObject *lhs_const; Py_ssize_t i; Py_ssize_t elts_len; @@ -637,14 +636,17 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) i = asdl_seq_LEN(ops) - 1; int op = asdl_seq_GET(ops, i); arg = asdl_seq_GET(args, i); - if ((node->v.Compare.left->kind) != Constant_kind) - return 1; - lhs_const = node->v.Compare.left->v.Constant.value; + _Bool is_lhs_constant = (node->v.Compare.left->kind) == Constant_kind; + //lhs_const = node->v.Compare.left->v.Constant.value; if (op == In || op == NotIn) { if (arg->kind == List_kind) { asdl_expr_seq *list_elts = arg->v.List.elts; if (has_starred(list_elts)) return 1; + expr_context_ty ctx = arg->v.List.ctx; + arg->kind = Tuple_kind; + arg->v.Tuple.elts = list_elts; + arg->v.Tuple.ctx = ctx; elts = list_elts; } else if (arg->kind == Dict_kind) { @@ -656,42 +658,45 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) else { return 1; } + elts_len = asdl_seq_LEN(elts); if (!elts_len) { return make_const(node, op == In ? Py_False : Py_True, arena); } - PyObject *newtuple = PyTuple_New(elts_len); - if (newtuple == NULL) { + + PyObject *newval = PyTuple_New(elts_len); + if (newval == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { return 0; } PyErr_Clear(); return 1; } + for (Py_ssize_t j = 0; j < elts_len; j++) { expr_ty e = (expr_ty)asdl_seq_GET(elts, j); if (e->kind != Constant_kind) { - PyObject_GC_UnTrack(newtuple); - PyObject_GC_Del(newtuple); - return 0; + PyObject_GC_UnTrack(newval); + PyObject_GC_Del(newval); + return 1; } PyObject *v = e->v.Constant.value; - PyTuple_SET_ITEM(newtuple, j, Py_NewRef(v)); - if (v == lhs_const && op == In) { - PyObject_GC_UnTrack(newtuple); - PyObject_GC_Del(newtuple); - return make_const(node, Py_True, arena); + PyTuple_SET_ITEM(newval, j, Py_NewRef(v)); + if (is_lhs_constant && + (v == (node->v.Compare.left->v.Constant.value))) + { + PyObject_GC_UnTrack(newval); + PyObject_GC_Del(newval); + return make_const(node, op == In ? Py_True : Py_False, arena); } } - if (op == NotIn) { - PyObject_GC_UnTrack(newtuple); - PyObject_GC_Del(newtuple); - return make_const(node, Py_True, arena); - } - return make_const(arg, newtuple, arena); + + if (arg->kind == Set_kind) + Py_SETREF(newval, PyFrozenSet_New(newval)); + return make_const(arg, newval, arena); } else if ((op == Eq || op == NotEq) && arg->kind == Constant_kind) { - if (lhs_const == arg->v.Constant.value) + if ((node->v.Compare.left->v.Constant.value) == (arg->v.Constant.value)) return make_const(node, op == Eq ? Py_True : Py_False, arena); } From 893e41d69b5f77f59beefb5e059c8c8c0e8b8fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Sun, 18 Aug 2024 17:47:24 +0300 Subject: [PATCH 3/8] Add one more check --- Python/ast_opt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index cc4c9f3afa6aba..11e2a31c9eeb1e 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -695,7 +695,10 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) Py_SETREF(newval, PyFrozenSet_New(newval)); return make_const(arg, newval, arena); } - else if ((op == Eq || op == NotEq) && arg->kind == Constant_kind) { + else if ((op == Eq || op == NotEq) && + (arg->kind == Constant_kind) && + is_lhs_constant) + { if ((node->v.Compare.left->v.Constant.value) == (arg->v.Constant.value)) return make_const(node, op == Eq ? Py_True : Py_False, arena); } From fa2bf5126c6446d879cf6f6b0f0bf88e7b96ca08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Mon, 19 Aug 2024 14:16:01 +0300 Subject: [PATCH 4/8] convert dict literal to set --- Python/ast_opt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 11e2a31c9eeb1e..46c7f18765dda1 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -651,6 +651,8 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) } else if (arg->kind == Dict_kind) { elts = arg->v.Dict.keys; + arg->kind = Set_kind; + arg->v.Set.elts = elts; } else if (arg->kind == Set_kind) { elts = arg->v.Set.elts; From 7ee9a65476d35ede506231c16772614c71032105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Tue, 20 Aug 2024 08:55:10 +0300 Subject: [PATCH 5/8] Add more braces and eliminate commented out code --- Python/ast_opt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 46c7f18765dda1..5cc74f450c9703 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -637,9 +637,9 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) int op = asdl_seq_GET(ops, i); arg = asdl_seq_GET(args, i); _Bool is_lhs_constant = (node->v.Compare.left->kind) == Constant_kind; - //lhs_const = node->v.Compare.left->v.Constant.value; + if (op == In || op == NotIn) { - if (arg->kind == List_kind) { + if ((arg->kind) == List_kind) { asdl_expr_seq *list_elts = arg->v.List.elts; if (has_starred(list_elts)) return 1; @@ -649,12 +649,12 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) arg->v.Tuple.ctx = ctx; elts = list_elts; } - else if (arg->kind == Dict_kind) { + else if ((arg->kind) == Dict_kind) { elts = arg->v.Dict.keys; arg->kind = Set_kind; arg->v.Set.elts = elts; } - else if (arg->kind == Set_kind) { + else if ((arg->kind) == Set_kind) { elts = arg->v.Set.elts; } else { @@ -693,15 +693,15 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) } } - if (arg->kind == Set_kind) + if ((arg->kind) == Set_kind) Py_SETREF(newval, PyFrozenSet_New(newval)); return make_const(arg, newval, arena); } - else if ((op == Eq || op == NotEq) && - (arg->kind == Constant_kind) && + else if (((op == Eq) || (op == NotEq)) && + ((arg->kind) == Constant_kind) && is_lhs_constant) { - if ((node->v.Compare.left->v.Constant.value) == (arg->v.Constant.value)) + if (((node->v.Compare.left)->v.Constant.value) == (arg->v.Constant.value)) return make_const(node, op == Eq ? Py_True : Py_False, arena); } From af11b23532c018f901a1f2399bd251f0c1723898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Tue, 20 Aug 2024 08:58:40 +0300 Subject: [PATCH 6/8] Use Py_DECREF instead of GC functions --- Python/ast_opt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 5cc74f450c9703..11f412ac0bcc82 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -678,8 +678,7 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) for (Py_ssize_t j = 0; j < elts_len; j++) { expr_ty e = (expr_ty)asdl_seq_GET(elts, j); if (e->kind != Constant_kind) { - PyObject_GC_UnTrack(newval); - PyObject_GC_Del(newval); + Py_DECREF(newval); return 1; } PyObject *v = e->v.Constant.value; @@ -687,8 +686,7 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) if (is_lhs_constant && (v == (node->v.Compare.left->v.Constant.value))) { - PyObject_GC_UnTrack(newval); - PyObject_GC_Del(newval); + Py_DECREF(newval); return make_const(node, op == In ? Py_True : Py_False, arena); } } From 4add36d6cae90fc98c6edf021b616f73dc1dda75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Tue, 20 Aug 2024 09:12:35 +0300 Subject: [PATCH 7/8] KeyboardInterrupt is no loanger handled --- Python/ast_opt.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 11f412ac0bcc82..cfa74f3469f4ba 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -668,9 +668,6 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) PyObject *newval = PyTuple_New(elts_len); if (newval == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { - return 0; - } PyErr_Clear(); return 1; } From 04192e238f59f0637f9583b154c7217b8e0524b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D0=BE=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=A0=D0=BE=D0=BC?= =?UTF-8?q?=D0=B0=D0=BD=D1=8E=D0=BA?= Date: Tue, 20 Aug 2024 09:17:26 +0300 Subject: [PATCH 8/8] Handle possible PyFrozenSet_New failure --- Python/ast_opt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Python/ast_opt.c b/Python/ast_opt.c index cfa74f3469f4ba..2ccae3bfafb142 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -688,8 +688,16 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) } } - if ((arg->kind) == Set_kind) - Py_SETREF(newval, PyFrozenSet_New(newval)); + if ((arg->kind) == Set_kind) { + PyObject *frozenset = PyFrozenSet_New(newval); + if (frozenset == NULL) { + PyErr_Clear(); + Py_DECREF(newval); + return 1; + } + Py_SETREF(newval, frozenset); + return make_const(arg, frozenset, arena); + } return make_const(arg, newval, arena); } else if (((op == Eq) || (op == NotEq)) &&