Skip to content

Commit 356b889

Browse files
[mypyc] feat: support constant folding in convert_format_expr_to_str [1/1] (#19970)
This PR adds support for constant folding inside of `convert_format_expr_to_str`
1 parent 269e7ee commit 356b889

3 files changed

Lines changed: 35 additions & 5 deletions

File tree

mypyc/irbuild/format_str_tokenizer.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
)
1313
from mypy.errors import Errors
1414
from mypy.messages import MessageBuilder
15-
from mypy.nodes import Context, Expression, StrExpr
15+
from mypy.nodes import Context, Expression
1616
from mypy.options import Options
1717
from mypyc.ir.ops import Integer, Value
1818
from mypyc.ir.rtypes import (
@@ -23,6 +23,7 @@
2323
is_str_rprimitive,
2424
)
2525
from mypyc.irbuild.builder import IRBuilder
26+
from mypyc.irbuild.constant_fold import constant_fold_expr
2627
from mypyc.primitives.bytes_ops import bytes_build_op
2728
from mypyc.primitives.int_ops import int_to_str_op
2829
from mypyc.primitives.str_ops import str_build_op, str_op
@@ -143,16 +144,18 @@ def convert_format_expr_to_str(
143144
for x, format_op in zip(exprs, format_ops):
144145
node_type = builder.node_type(x)
145146
if format_op == FormatOp.STR:
146-
if is_str_rprimitive(node_type) or isinstance(
147-
x, StrExpr
148-
): # NOTE: why does mypyc think our fake StrExprs are not str rprimitives?
147+
if isinstance(folded := constant_fold_expr(builder, x), str):
148+
var_str = builder.load_literal_value(folded)
149+
elif is_str_rprimitive(node_type):
149150
var_str = builder.accept(x)
150151
elif is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type):
151152
var_str = builder.primitive_op(int_to_str_op, [builder.accept(x)], line)
152153
else:
153154
var_str = builder.primitive_op(str_op, [builder.accept(x)], line)
154155
elif format_op == FormatOp.INT:
155-
if is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type):
156+
if isinstance(folded := constant_fold_expr(builder, x), int):
157+
var_str = builder.load_literal_value(str(folded))
158+
elif is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type):
156159
var_str = builder.primitive_op(int_to_str_op, [builder.accept(x)], line)
157160
else:
158161
return None

mypyc/test-data/irbuild-constant-fold.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,25 @@ L0:
186186
big5 = r4
187187
return 1
188188

189+
[case testConstantFoldFormatArgs]
190+
# This only tests that the callee and args are constant folded,
191+
# it is not intended to test the result.
192+
from typing import Any, Final
193+
194+
FMT: Final = "{} {}"
195+
196+
def f() -> str:
197+
return FMT.format(400 + 20, "roll" + "up")
198+
[out]
199+
def f():
200+
r0, r1, r2, r3 :: str
201+
L0:
202+
r0 = CPyTagged_Str(840)
203+
r1 = 'rollup'
204+
r2 = ' '
205+
r3 = CPyStr_Build(3, r0, r2, r1)
206+
return r3
207+
189208
[case testIntConstantFoldingFinal]
190209
from typing import Final
191210
X: Final = 5

mypyc/test-data/run-strings.test

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,3 +1249,11 @@ def test_optional_ne() -> None:
12491249
assert ne_s_opt_s_opt('y', 'x')
12501250
assert ne_s_opt_s_opt(None, 'x')
12511251
assert ne_s_opt_s_opt('x', None)
1252+
1253+
[case testConstantFoldFormatArgs]
1254+
from typing import Final
1255+
1256+
FMT: Final = "{} {}"
1257+
1258+
def test_format() -> None:
1259+
assert FMT.format(400 + 20, "roll" + "up") == "420 rollup"

0 commit comments

Comments
 (0)