-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
feat: add IndexExpr support to constant_fold_expr [1/2]
#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 all 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
9c9743c
e854bdb
b2524ab
979ee73
c24e67e
98ed412
8784efa
857fe55
0d0ae5d
66c40bd
9f71e3f
598c7f8
aaa4a19
2cbcd95
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,26 @@ | |
|
|
||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING, Final | ||
| from collections.abc import Callable, Sequence | ||
| from typing import TYPE_CHECKING, Final, TypeVar | ||
|
|
||
| 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: | ||
|
|
@@ -35,6 +39,8 @@ | |
| ConstantValue = int | float | complex | str | bytes | ||
| CONST_TYPES: Final = (int, float, complex, str, bytes) | ||
|
|
||
| Expr = TypeVar("Expr", bound=Expression) | ||
|
|
||
|
|
||
| def constant_fold_expr(builder: IRBuilder, expr: Expression) -> ConstantValue | None: | ||
| """Return the constant value of an expression for supported operations. | ||
|
|
@@ -74,6 +80,60 @@ 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: | ||
BobTheBuidler marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert isinstance(base, (Sequence, dict)), base | ||
| 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 | ||
|
|
||
| # this branching just keeps mypy happy, non-functional | ||
| if isinstance(base, Sequence): | ||
| assert isinstance(begin_index, int) or begin_index is None | ||
| assert isinstance(end_index, int) or end_index is None | ||
| assert isinstance(stride, int) or stride is None | ||
| try: | ||
| return base[begin_index:end_index:stride] | ||
| except Exception: | ||
| return None | ||
| try: # type: ignore [unreachable] | ||
| return base[begin_index:end_index:stride] | ||
| except Exception: | ||
| return None | ||
|
|
||
| index = constant_fold_expr(builder, index_expr) | ||
|
|
||
| # this branching just keeps mypy happy, non-functional | ||
| if isinstance(base, Sequence): | ||
|
|
||
| if isinstance(index, int): | ||
| try: | ||
| return base[index] | ||
| except Exception: | ||
| return None | ||
| else: | ||
| try: # type: ignore [unreachable] | ||
| return base[index] | ||
| except Exception: | ||
| return None | ||
| return None | ||
|
|
||
|
|
||
|
|
@@ -95,3 +155,31 @@ 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( | ||
|
Contributor
Author
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, Expr], Value], | ||
| ) -> Callable[[IRBuilder, Expr], Value]: | ||
| """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: Expr) -> Value: | ||
| 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
baseis a Sequence -- you can index anint, for example.