-
-
Notifications
You must be signed in to change notification settings - Fork 3k
feat: add IndexExpr support to constant_fold_expr
[1/1]
#19982
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
base: master
Are you sure you want to change the base?
Changes from 22 commits
970cd4f
51fdd2d
4ad507a
bed37d6
d7f75f4
558dee1
3f18ed0
692844c
869616c
22651fe
9bd78f3
60574fc
daeaa50
785c221
817ab5b
042f726
fe2f670
377b31e
adae39f
35b0dfc
6a25595
8add115
286a108
0a14359
2d768df
4bcd5d6
a62ef3a
3ff12ec
45bcc66
e2fa664
27193d8
4dc3a78
9481314
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 |
---|---|---|
|
@@ -10,22 +10,25 @@ | |
|
||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING, Final, Union | ||
from typing import TYPE_CHECKING, Callable, Final, Union | ||
|
||
from mypy.constant_fold import constant_fold_binary_op, constant_fold_unary_op | ||
from mypy.nodes import ( | ||
BytesExpr, | ||
ComplexExpr, | ||
Expression, | ||
FloatExpr, | ||
IndexExpr, | ||
IntExpr, | ||
MemberExpr, | ||
NameExpr, | ||
OpExpr, | ||
SliceExpr, | ||
StrExpr, | ||
UnaryExpr, | ||
Var, | ||
) | ||
from mypyc.ir.ops import Value | ||
from mypyc.irbuild.util import bytes_from_str | ||
|
||
if TYPE_CHECKING: | ||
|
@@ -74,6 +77,40 @@ def constant_fold_expr(builder: IRBuilder, expr: Expression) -> ConstantValue | | |
value = constant_fold_expr(builder, expr.expr) | ||
if value is not None and not isinstance(value, bytes): | ||
return constant_fold_unary_op(expr.op, value) | ||
elif isinstance(expr, IndexExpr): | ||
base = constant_fold_expr(builder, expr.base) | ||
if base is not None: | ||
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. Similar -- check if base is a Sequence? 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 left out the type check to make it maximally receptive to future constant folding changes For example, while we can't constant fold a dict value as a real constant, we can constant fold it as an intermediate step of an existing constant fold This isn't relevant at the moment, as Sequence would catch all existing cases, but it will be relevant in the coming weeks as I keep enhancing our folding capabilities 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. In either case the program is still safe to run in its current state, but only with the None check do we get future extensibility built in |
||
index_expr = expr.index | ||
if isinstance(index_expr, SliceExpr): | ||
if index_expr.begin_index is None: | ||
begin_index = None | ||
else: | ||
begin_index = constant_fold_expr(builder, index_expr.begin_index) | ||
if begin_index is None: | ||
return None | ||
if index_expr.end_index is None: | ||
end_index = None | ||
else: | ||
end_index = constant_fold_expr(builder, index_expr.end_index) | ||
if end_index is None: | ||
return None | ||
if index_expr.stride is None: | ||
stride = None | ||
else: | ||
stride = constant_fold_expr(builder, index_expr.stride) | ||
if stride is None: | ||
return None | ||
try: | ||
return base[begin_index:end_index:stride] # type: ignore [index, misc] | ||
except Exception: | ||
return None | ||
|
||
index = constant_fold_expr(builder, index_expr) | ||
if index is not None: | ||
try: | ||
return base[index] # type: ignore [index] | ||
except Exception: | ||
return None | ||
return None | ||
|
||
|
||
|
@@ -95,3 +132,29 @@ def constant_fold_binary_op_extended( | |
return left * right | ||
|
||
return None | ||
|
||
|
||
def try_constant_fold(builder: IRBuilder, expr: Expression) -> Value | None: | ||
"""Return the constant value of an expression if possible. | ||
|
||
Return None otherwise. | ||
""" | ||
value = constant_fold_expr(builder, expr) | ||
if value is not None: | ||
return builder.load_literal_value(value) | ||
return None | ||
|
||
|
||
def folding_candidate( | ||
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. This is a new decorator that lets us deduplicate existing folding code and also sets me up for cleaner implementation of folding transformations of cast and comparison when those PRs are ready I think you'll likely agree that both of these functions are better suited here in the constant folding file |
||
transform: Callable[[IRBuilder, Expression], Value | None], | ||
) -> Callable[[IRBuilder, Expression], Value | None]: | ||
"""Mark a transform function as a candidate for constant folding. | ||
|
||
Candidate functions will attempt to short-circuit the transformation | ||
by constant folding the expression and will only proceed to transform | ||
the expression if folding is not possible. | ||
""" | ||
def constant_fold_wrap(builder: IRBuilder, expr: Expression) -> Value | None: | ||
folded = try_constant_fold(builder, expr) | ||
return folded if folded is not None else transform(builder, expr) | ||
return constant_fold_wrap |
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.
I think it would be better to check if
base
is a Sequence -- you can index anint
, for example.