From 12e0a9d0b60895a53b59900867016d5fed81fdcb Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:42:20 -0400 Subject: [PATCH 01/28] WIP [mypyc] optimize f-string building --- mypyc/irbuild/specialize.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 3015640fb3fd..71ecb341b52d 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -710,6 +710,15 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va format_ops.append(FormatOp.STR) exprs.append(item.args[0]) + for i in range(len(exprs)): + # TODO: instead of checking isinstance StrExpr, check with some new is_literal fn. + # This can include IntExpr, BytesExpr, Final string RefExpr, and more future cases. + while isinstance(exprs[i], StrExpr) and isinstance(exprs[i+1], StrExpr): + first = exprs[i] + concatenated = first.value + exprs[i+1].value + exprs = [exprs[:i] + [StrExpr(concatenated, first.line)] + exprs[i+2:]] + format_ops = format_ops[:i] + [format_ops[i+1]] + [format_ops[i+2:] + substitutions = convert_format_expr_to_str(builder, format_ops, exprs, expr.line) if substitutions is None: return None From 5b44af15c1623a702080271835a20e38762f42c6 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:43:35 -0400 Subject: [PATCH 02/28] Update specialize.py --- mypyc/irbuild/specialize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 71ecb341b52d..3ad519f4e2fd 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -716,8 +716,8 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va while isinstance(exprs[i], StrExpr) and isinstance(exprs[i+1], StrExpr): first = exprs[i] concatenated = first.value + exprs[i+1].value - exprs = [exprs[:i] + [StrExpr(concatenated, first.line)] + exprs[i+2:]] - format_ops = format_ops[:i] + [format_ops[i+1]] + [format_ops[i+2:] + exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i+2:]] + format_ops = [*format_ops[:i], format_ops[i+1], *format_ops[i+2:]] substitutions = convert_format_expr_to_str(builder, format_ops, exprs, expr.line) if substitutions is None: From fc40c8169d550d55dd349f09598fb7dd4f487298 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 23:45:26 +0000 Subject: [PATCH 03/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/specialize.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 3ad519f4e2fd..e591b611054c 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -713,11 +713,11 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va for i in range(len(exprs)): # TODO: instead of checking isinstance StrExpr, check with some new is_literal fn. # This can include IntExpr, BytesExpr, Final string RefExpr, and more future cases. - while isinstance(exprs[i], StrExpr) and isinstance(exprs[i+1], StrExpr): + while isinstance(exprs[i], StrExpr) and isinstance(exprs[i + 1], StrExpr): first = exprs[i] - concatenated = first.value + exprs[i+1].value - exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i+2:]] - format_ops = [*format_ops[:i], format_ops[i+1], *format_ops[i+2:]] + concatenated = first.value + exprs[i + 1].value + exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i + 2 :]] + format_ops = [*format_ops[:i], format_ops[i + 1], *format_ops[i + 2 :]] substitutions = convert_format_expr_to_str(builder, format_ops, exprs, expr.line) if substitutions is None: From 61970f5e3b4a137a726f1a30cf84a7525238d477 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Thu, 7 Aug 2025 19:57:51 -0400 Subject: [PATCH 04/28] Update specialize.py --- mypyc/irbuild/specialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index e591b611054c..421e5654067e 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -710,7 +710,7 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va format_ops.append(FormatOp.STR) exprs.append(item.args[0]) - for i in range(len(exprs)): + for i in range(len(exprs) - 1): # TODO: instead of checking isinstance StrExpr, check with some new is_literal fn. # This can include IntExpr, BytesExpr, Final string RefExpr, and more future cases. while isinstance(exprs[i], StrExpr) and isinstance(exprs[i + 1], StrExpr): From c5ebd11d0300623cd4030a4450e86fb9803adac8 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:48:49 -0400 Subject: [PATCH 05/28] Update specialize.py --- mypyc/irbuild/specialize.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 421e5654067e..705f27589f0e 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -713,9 +713,21 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va for i in range(len(exprs) - 1): # TODO: instead of checking isinstance StrExpr, check with some new is_literal fn. # This can include IntExpr, BytesExpr, Final string RefExpr, and more future cases. - while isinstance(exprs[i], StrExpr) and isinstance(exprs[i + 1], StrExpr): + + # NOTE: not sure where I should put these helpers + def is_literal_str(expr: Expression) -> bool: + return isinstance(expr, StrExpr) or isinstance(expr, RefExpr) and expr.is_final + + def get_literal_str(expr: Expression) -> str | None: + if isinstance(expr, StrExpr): + return expr.value + elif isinstance(expr, RefExpr) and expr.is_final: + return expr.final_value + return None + + while is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): first = exprs[i] - concatenated = first.value + exprs[i + 1].value + concatenated = get_literal_str(first) + get_literal_str(exprs[i + 1]) exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i + 2 :]] format_ops = [*format_ops[:i], format_ops[i + 1], *format_ops[i + 2 :]] From 8a6880040924a8affe46b8c33d0da1aec84d3995 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:52:26 -0400 Subject: [PATCH 06/28] Update specialize.py --- mypyc/irbuild/specialize.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 705f27589f0e..d345b94f066f 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -716,13 +716,13 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va # NOTE: not sure where I should put these helpers def is_literal_str(expr: Expression) -> bool: - return isinstance(expr, StrExpr) or isinstance(expr, RefExpr) and expr.is_final + return isinstance(expr, StrExpr) or isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.final_value is not None def get_literal_str(expr: Expression) -> str | None: if isinstance(expr, StrExpr): return expr.value - elif isinstance(expr, RefExpr) and expr.is_final: - return expr.final_value + elif isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.is_final: + return str(expr.final_value) return None while is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): From 996d852d9535dcbb6b939e189f4ea213d5a769b2 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:53:13 -0400 Subject: [PATCH 07/28] Update specialize.py --- mypyc/irbuild/specialize.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index d345b94f066f..6149e54f1aa7 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -711,9 +711,6 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va exprs.append(item.args[0]) for i in range(len(exprs) - 1): - # TODO: instead of checking isinstance StrExpr, check with some new is_literal fn. - # This can include IntExpr, BytesExpr, Final string RefExpr, and more future cases. - # NOTE: not sure where I should put these helpers def is_literal_str(expr: Expression) -> bool: return isinstance(expr, StrExpr) or isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.final_value is not None From 3fe0a63e7bd2483416ec2da86ea5c21300052844 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:53:48 -0400 Subject: [PATCH 08/28] Update specialize.py --- mypyc/irbuild/specialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 6149e54f1aa7..9b2db6688d44 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -718,7 +718,7 @@ def is_literal_str(expr: Expression) -> bool: def get_literal_str(expr: Expression) -> str | None: if isinstance(expr, StrExpr): return expr.value - elif isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.is_final: + elif isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.final_value is not None: return str(expr.final_value) return None From c817b677fcf93d5cea54b7d47c8f4a91a3786583 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:58:35 -0400 Subject: [PATCH 09/28] Update specialize.py --- mypyc/irbuild/specialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 9b2db6688d44..1443dcb37438 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -722,7 +722,7 @@ def get_literal_str(expr: Expression) -> str | None: return str(expr.final_value) return None - while is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): + while len(exprs) >= i + 2 and is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): first = exprs[i] concatenated = get_literal_str(first) + get_literal_str(exprs[i + 1]) exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i + 2 :]] From 8636006619c0ded4ce5c8c49f97983549887de6b Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:02:32 -0400 Subject: [PATCH 10/28] Update specialize.py --- mypyc/irbuild/specialize.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 1443dcb37438..9fa2a8021246 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -31,6 +31,7 @@ RefExpr, StrExpr, TupleExpr, + Var, ) from mypy.types import AnyType, TypeOfAny from mypyc.ir.ops import ( @@ -719,12 +720,12 @@ def get_literal_str(expr: Expression) -> str | None: if isinstance(expr, StrExpr): return expr.value elif isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.final_value is not None: - return str(expr.final_value) + return str(expr.node.final_value) return None while len(exprs) >= i + 2 and is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): first = exprs[i] - concatenated = get_literal_str(first) + get_literal_str(exprs[i + 1]) + concatenated = get_literal_str(first) + get_literal_str(exprs[i + 1]) # type: ignore [operator] exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i + 2 :]] format_ops = [*format_ops[:i], format_ops[i + 1], *format_ops[i + 2 :]] From 5cee24340400cb4e32cf94476361b5d17edb58d4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:03:15 -0400 Subject: [PATCH 11/28] Update specialize.py --- mypyc/irbuild/specialize.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 9fa2a8021246..9911589d2e36 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -725,8 +725,8 @@ def get_literal_str(expr: Expression) -> str | None: while len(exprs) >= i + 2 and is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): first = exprs[i] - concatenated = get_literal_str(first) + get_literal_str(exprs[i + 1]) # type: ignore [operator] - exprs = [*exprs[:i], StrExpr(concatenated, first.line), *exprs[i + 2 :]] + concatenated = StrExpr(get_literal_str(first) + get_literal_str(exprs[i + 1])) # type: ignore [operator] + exprs = [*exprs[:i], concatenated, *exprs[i + 2 :]] format_ops = [*format_ops[:i], format_ops[i + 1], *format_ops[i + 2 :]] substitutions = convert_format_expr_to_str(builder, format_ops, exprs, expr.line) From 8b50424a8072bf7c9ef056d2314330ee6a26b57c Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:04:07 -0400 Subject: [PATCH 12/28] Update specialize.py --- mypyc/irbuild/specialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 9911589d2e36..ddd4eec70bc6 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -727,7 +727,7 @@ def get_literal_str(expr: Expression) -> str | None: first = exprs[i] concatenated = StrExpr(get_literal_str(first) + get_literal_str(exprs[i + 1])) # type: ignore [operator] exprs = [*exprs[:i], concatenated, *exprs[i + 2 :]] - format_ops = [*format_ops[:i], format_ops[i + 1], *format_ops[i + 2 :]] + format_ops = [*format_ops[:i], FormatOp.STR, *format_ops[i + 2 :]] substitutions = convert_format_expr_to_str(builder, format_ops, exprs, expr.line) if substitutions is None: From 712b10a55fc89c629bb52956df4b4e863b5b2b66 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:09:45 -0400 Subject: [PATCH 13/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 3e69325a454b..1770cae7b4e4 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -605,3 +605,19 @@ L3: r6 = r7 L4: return r6 + +[case testFStringFromConstants] +from typing import Final +string: Final = "abc" +integer: Final = 123 +floating: Final = 3.14 + +def test(x: str) -> str: + return f"{string}{integer}{floating}{x}" + +[out] +def test(x): + x, r0 :: str + +L0: + 'abc1233.14 ' From ad588501bd7be32ca7bac7621ba0389237fe269a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 21:30:53 +0000 Subject: [PATCH 14/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/specialize.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index ddd4eec70bc6..056ab31b4a40 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -714,16 +714,27 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va for i in range(len(exprs) - 1): # NOTE: not sure where I should put these helpers def is_literal_str(expr: Expression) -> bool: - return isinstance(expr, StrExpr) or isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.final_value is not None - + return ( + isinstance(expr, StrExpr) + or isinstance(expr, RefExpr) + and isinstance(expr.node, Var) + and expr.node.final_value is not None + ) + def get_literal_str(expr: Expression) -> str | None: if isinstance(expr, StrExpr): return expr.value - elif isinstance(expr, RefExpr) and isinstance(expr.node, Var) and expr.node.final_value is not None: + elif ( + isinstance(expr, RefExpr) + and isinstance(expr.node, Var) + and expr.node.final_value is not None + ): return str(expr.node.final_value) return None - - while len(exprs) >= i + 2 and is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]): + + while ( + len(exprs) >= i + 2 and is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]) + ): first = exprs[i] concatenated = StrExpr(get_literal_str(first) + get_literal_str(exprs[i + 1])) # type: ignore [operator] exprs = [*exprs[:i], concatenated, *exprs[i + 2 :]] From a69ea3fac3fd0b04cf13b0a1ff3753920d4aae1a Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:49:53 -0400 Subject: [PATCH 15/28] Update format_str_tokenizer.py --- mypyc/irbuild/format_str_tokenizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/format_str_tokenizer.py b/mypyc/irbuild/format_str_tokenizer.py index eaa4027ed768..a5ead21681e4 100644 --- a/mypyc/irbuild/format_str_tokenizer.py +++ b/mypyc/irbuild/format_str_tokenizer.py @@ -143,7 +143,7 @@ def convert_format_expr_to_str( for x, format_op in zip(exprs, format_ops): node_type = builder.node_type(x) if format_op == FormatOp.STR: - if is_str_rprimitive(node_type): + if is_str_rprimitive(node_type) or isinstance(x, StrExpr): # NOTE: why does mypyc think our fake StrExprs are not str rprimitives? var_str = builder.accept(x) elif is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type): var_str = builder.primitive_op(int_to_str_op, [builder.accept(x)], line) From 5351050563b0ddf0cd53bd47835a4834eb0079b1 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:50:04 -0400 Subject: [PATCH 16/28] Update format_str_tokenizer.py --- mypyc/irbuild/format_str_tokenizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/format_str_tokenizer.py b/mypyc/irbuild/format_str_tokenizer.py index a5ead21681e4..f2f71f64ae48 100644 --- a/mypyc/irbuild/format_str_tokenizer.py +++ b/mypyc/irbuild/format_str_tokenizer.py @@ -12,7 +12,7 @@ ) from mypy.errors import Errors from mypy.messages import MessageBuilder -from mypy.nodes import Context, Expression +from mypy.nodes import Context, Expression, StrExpr from mypy.options import Options from mypyc.ir.ops import Integer, Value from mypyc.ir.rtypes import ( From 5b32541242973918db9eb339057a336a1a80d17c Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:05:02 -0400 Subject: [PATCH 17/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 1770cae7b4e4..3a18a9419a99 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -617,7 +617,9 @@ def test(x: str) -> str: [out] def test(x): - x, r0 :: str + x, r0, r1 :: str L0: - 'abc1233.14 ' + r0 = 'abc1233.14' + r1 = CPyStrBuild(2, r0, x) + return r1 From 0a03849e4e7a66ba6b33bd439975e7148e5c6c36 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:16:19 -0400 Subject: [PATCH 18/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 3a18a9419a99..87f8002d8307 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -621,5 +621,5 @@ def test(x): L0: r0 = 'abc1233.14' - r1 = CPyStrBuild(2, r0, x) + r1 = CPyStr_Build(2, r0, x) return r1 From a68c9f8e45cc6326491d7fc3298d3d6e7711f9aa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 22:17:36 +0000 Subject: [PATCH 19/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/format_str_tokenizer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypyc/irbuild/format_str_tokenizer.py b/mypyc/irbuild/format_str_tokenizer.py index f2f71f64ae48..5a35900006d2 100644 --- a/mypyc/irbuild/format_str_tokenizer.py +++ b/mypyc/irbuild/format_str_tokenizer.py @@ -143,7 +143,9 @@ def convert_format_expr_to_str( for x, format_op in zip(exprs, format_ops): node_type = builder.node_type(x) if format_op == FormatOp.STR: - if is_str_rprimitive(node_type) or isinstance(x, StrExpr): # NOTE: why does mypyc think our fake StrExprs are not str rprimitives? + if is_str_rprimitive(node_type) or isinstance( + x, StrExpr + ): # NOTE: why does mypyc think our fake StrExprs are not str rprimitives? var_str = builder.accept(x) elif is_int_rprimitive(node_type) or is_short_int_rprimitive(node_type): var_str = builder.primitive_op(int_to_str_op, [builder.accept(x)], line) From 0216858266f7464bc29682dd28bb6e51ae5d212c Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:23:57 -0400 Subject: [PATCH 20/28] Update specialize.py --- mypyc/irbuild/specialize.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index 056ab31b4a40..e3349ec0cb03 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -712,16 +712,8 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va exprs.append(item.args[0]) for i in range(len(exprs) - 1): - # NOTE: not sure where I should put these helpers - def is_literal_str(expr: Expression) -> bool: - return ( - isinstance(expr, StrExpr) - or isinstance(expr, RefExpr) - and isinstance(expr.node, Var) - and expr.node.final_value is not None - ) - def get_literal_str(expr: Expression) -> str | None: + # NOTE: not sure where I should put this helper, this file? somewhere else? if isinstance(expr, StrExpr): return expr.value elif ( @@ -733,11 +725,11 @@ def get_literal_str(expr: Expression) -> str | None: return None while ( - len(exprs) >= i + 2 and is_literal_str(exprs[i]) and is_literal_str(exprs[i + 1]) + len(exprs) >= i + 2 + and (first := get_literal_str(exprs[i])) is not None + and (second := get_literal_str(exprs[i + 1])) is not None ): - first = exprs[i] - concatenated = StrExpr(get_literal_str(first) + get_literal_str(exprs[i + 1])) # type: ignore [operator] - exprs = [*exprs[:i], concatenated, *exprs[i + 2 :]] + exprs = [*exprs[:i], StrExpr(first + second), *exprs[i + 2 :]] format_ops = [*format_ops[:i], FormatOp.STR, *format_ops[i + 2 :]] substitutions = convert_format_expr_to_str(builder, format_ops, exprs, expr.line) From 6047b0fc155f1435289f5e137ea7dc42e46fe913 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:25:46 -0400 Subject: [PATCH 21/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 87f8002d8307..df2172340c66 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -613,13 +613,15 @@ integer: Final = 123 floating: Final = 3.14 def test(x: str) -> str: - return f"{string}{integer}{floating}{x}" + return f"{string}{integer}{floating}{x}{floating}{integer}{string}{x}{string}{integer}{floating}{x}" [out] def test(x): - x, r0, r1 :: str + x, r0, r1, r2, r3 :: str L0: r0 = 'abc1233.14' - r1 = CPyStr_Build(2, r0, x) - return r1 + r1 = '3.14123abc' + r2 = 'abc1233.14' + r3 = CPyStr_Build(2, r0, x, r1, x, r2) + return r3 From 7b3ca5b1074899319193e95a8b4ffdf2cf8a2c50 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 22:34:03 +0000 Subject: [PATCH 22/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/specialize.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypyc/irbuild/specialize.py b/mypyc/irbuild/specialize.py index e3349ec0cb03..0fa5cf71d016 100644 --- a/mypyc/irbuild/specialize.py +++ b/mypyc/irbuild/specialize.py @@ -712,6 +712,7 @@ def translate_fstring(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Va exprs.append(item.args[0]) for i in range(len(exprs) - 1): + def get_literal_str(expr: Expression) -> str | None: # NOTE: not sure where I should put this helper, this file? somewhere else? if isinstance(expr, StrExpr): From ceb0e031dcfba0875b6a3f258e3138fca865aea8 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:38:10 -0400 Subject: [PATCH 23/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index df2172340c66..891e5bc2c9df 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -623,5 +623,5 @@ L0: r0 = 'abc1233.14' r1 = '3.14123abc' r2 = 'abc1233.14' - r3 = CPyStr_Build(2, r0, x, r1, x, r2) + r3 = CPyStr_Build(6, r0, x, r1, x, r2, x) return r3 From ba03d50141efc3b238ce9dda43222280c9179021 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:40:51 -0400 Subject: [PATCH 24/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 891e5bc2c9df..3567d29a9ee0 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -611,17 +611,18 @@ from typing import Final string: Final = "abc" integer: Final = 123 floating: Final = 3.14 +comp: Final = 3 + 4j def test(x: str) -> str: - return f"{string}{integer}{floating}{x}{floating}{integer}{string}{x}{string}{integer}{floating}{x}" + return f"{string}{integer}{floating}{comp}{x}{comp}{floating}{integer}{string}{x}{string}{integer}{floating}{comp}{x}" [out] def test(x): x, r0, r1, r2, r3 :: str L0: - r0 = 'abc1233.14' - r1 = '3.14123abc' - r2 = 'abc1233.14' + r0 = 'abc1233.14(3+4j)' + r1 = '(3+4j)3.14123abc' + r2 = 'abc1233.14(3+4j)' r3 = CPyStr_Build(6, r0, x, r1, x, r2, x) return r3 From fc973dff6d54653d99e34099148a76311c81983d Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:54:10 -0400 Subject: [PATCH 25/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 3567d29a9ee0..f94a4f9e3f8b 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -611,18 +611,19 @@ from typing import Final string: Final = "abc" integer: Final = 123 floating: Final = 3.14 -comp: Final = 3 + 4j +boolean: Final = True +none: Final = None def test(x: str) -> str: - return f"{string}{integer}{floating}{comp}{x}{comp}{floating}{integer}{string}{x}{string}{integer}{floating}{comp}{x}" + return f"{string}{integer}{floating}{boolean}{none}{x}{none}{boolean}{floating}{integer}{string}{x}{string}{integer}{floating}{boolean}{none}{x}" [out] def test(x): x, r0, r1, r2, r3 :: str L0: - r0 = 'abc1233.14(3+4j)' - r1 = '(3+4j)3.14123abc' - r2 = 'abc1233.14(3+4j)' + r0 = 'abc1233.14TrueNone' + r1 = 'NoneTrue3.14123abc' + r2 = 'abc1233.14TrueNone' r3 = CPyStr_Build(6, r0, x, r1, x, r2, x) return r3 From 029b6576f0fb75fd31808ef2e609a41d1a3ba6e5 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:54:57 -0400 Subject: [PATCH 26/28] Update irbuild-str.test --- mypyc/test-data/irbuild-str.test | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index f94a4f9e3f8b..a959d437c2be 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -612,18 +612,17 @@ string: Final = "abc" integer: Final = 123 floating: Final = 3.14 boolean: Final = True -none: Final = None def test(x: str) -> str: - return f"{string}{integer}{floating}{boolean}{none}{x}{none}{boolean}{floating}{integer}{string}{x}{string}{integer}{floating}{boolean}{none}{x}" + return f"{string}{integer}{floating}{boolean}{x}{boolean}{floating}{integer}{string}{x}{string}{integer}{floating}{boolean}{x}" [out] def test(x): x, r0, r1, r2, r3 :: str L0: - r0 = 'abc1233.14TrueNone' - r1 = 'NoneTrue3.14123abc' - r2 = 'abc1233.14TrueNone' + r0 = 'abc1233.14True' + r1 = 'True3.14123abc' + r2 = 'abc1233.14True' r3 = CPyStr_Build(6, r0, x, r1, x, r2, x) return r3 From 806484518076565b4f353e2a633e00aa6c531ee0 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Mon, 11 Aug 2025 23:09:53 +0000 Subject: [PATCH 27/28] fix ir whitespace --- mypyc/test-data/irbuild-str.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index a959d437c2be..8bf233036808 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -619,10 +619,10 @@ def test(x: str) -> str: [out] def test(x): x, r0, r1, r2, r3 :: str - L0: r0 = 'abc1233.14True' r1 = 'True3.14123abc' r2 = 'abc1233.14True' r3 = CPyStr_Build(6, r0, x, r1, x, r2, x) return r3 + From 55c4a8da3d3b579ce035e075676164fee456e8a5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 23:11:18 +0000 Subject: [PATCH 28/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/test-data/irbuild-str.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/test-data/irbuild-str.test b/mypyc/test-data/irbuild-str.test index 8bf233036808..54afa771ab2b 100644 --- a/mypyc/test-data/irbuild-str.test +++ b/mypyc/test-data/irbuild-str.test @@ -625,4 +625,3 @@ L0: r2 = 'abc1233.14True' r3 = CPyStr_Build(6, r0, x, r1, x, r2, x) return r3 -