-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-128706: Evaluate constant comparisons in fold_compare
#128705
Changes from all commits
de026a9
22bcb10
713fde5
285f266
c3abf4a
5cb7cd8
65093fb
891bff5
4f5f1b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -210,6 +210,10 @@ configuration mechanisms). | |||||
|
||||||
Other language changes | ||||||
====================== | ||||||
* Constant comparsion expressions are now folded and evaluated before runtime. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know how we are actually ordering the changes. Since this is a fairly niche optimization, I would put it at the end of the list. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually, new changes are added at the end of a section. |
||||||
For example, expressions like: ``"str" in ("str",)`` or ``1 == 1.0 == True`` | ||||||
are now pre-evaluated. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
(Contributed by Yan Yanchii in :gh:`128706`.) | ||||||
|
||||||
* The :func:`map` built-in now has an optional keyword-only *strict* flag | ||||||
like :func:`zip` to check that all the iterables are of equal length. | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add constant folding for constant comparisons. |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -639,6 +639,68 @@ fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) | |||||
return 0; | ||||||
} | ||||||
} | ||||||
|
||||||
static const int richcompare_table[] = { | ||||||
[Eq] = Py_EQ, | ||||||
[NotEq] = Py_NE, | ||||||
[Gt] = Py_GT, | ||||||
[Lt] = Py_LT, | ||||||
[GtE] = Py_GE, | ||||||
[LtE] = Py_LE, | ||||||
}; | ||||||
|
||||||
if (node->v.Compare.left->kind == Constant_kind) { | ||||||
PyObject *lhs = node->v.Compare.left->v.Constant.value; | ||||||
for (Py_ssize_t i = 0; i < asdl_seq_LEN(args); i++) { | ||||||
expr_ty curr_expr = (expr_ty)asdl_seq_GET(args, i); | ||||||
if (curr_expr->kind != Constant_kind) { | ||||||
/* try to fold only if every comparator is constant */ | ||||||
picnixz marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
return 1; | ||||||
} | ||||||
int op = asdl_seq_GET(ops, i); | ||||||
if (op == Is || op == IsNot) { | ||||||
/* Do not fold "is" and "is not" expressions since this breaks | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
expected syntax warnings. For example: | ||||||
>>> 1 is 1 | ||||||
<python-input-0>:1: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? | ||||||
*/ | ||||||
return 1; | ||||||
} | ||||||
PyObject *rhs = curr_expr->v.Constant.value; | ||||||
int res; | ||||||
switch (op) { | ||||||
case Eq: | ||||||
case NotEq: | ||||||
case Gt: | ||||||
case Lt: | ||||||
case GtE: | ||||||
case LtE: { | ||||||
res = PyObject_RichCompareBool(lhs, rhs, richcompare_table[op]); | ||||||
break; | ||||||
} | ||||||
case In: | ||||||
case NotIn: { | ||||||
res = PySequence_Contains(rhs, lhs); | ||||||
if (op == NotIn && res >= 0) { | ||||||
res = !res; | ||||||
} | ||||||
break; | ||||||
} | ||||||
default: | ||||||
Py_UNREACHABLE(); | ||||||
} | ||||||
if (res == 0) { | ||||||
/* shortcut, whole expression is False */ | ||||||
return make_const(node, Py_False, arena); | ||||||
} | ||||||
else if (res < 0) { | ||||||
return make_const(node, NULL, arena); | ||||||
} | ||||||
picnixz marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
lhs = rhs; | ||||||
} | ||||||
/* whole expression is True */ | ||||||
return make_const(node, Py_True, arena); | ||||||
} | ||||||
return 1; | ||||||
} | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a terminology that would be like "at compilation time" instead of "before runtime"? (using "compilation" time may cause users to think that it's only when
.pyc
files are created but this can be skipped with-B
I think?)