From 970dcb53eb8cd3f667e698c9d473b5f6fd9856e2 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 06:27:05 +0000 Subject: [PATCH 01/23] [mypyc] feat: support RTuple in `sequence_from_generator_preallocate_helper` --- mypyc/irbuild/for_helpers.py | 38 +++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 5edee6cb4df4..efc64c7fc537 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -212,10 +212,9 @@ def sequence_from_generator_preallocate_helper( there is no condition list in the generator and only one original sequence with one index is allowed. - e.g. (1) tuple(f(x) for x in a_list/a_tuple/a_str/a_bytes) - (2) list(f(x) for x in a_list/a_tuple/a_str/a_bytes) - (3) [f(x) for x in a_list/a_tuple/a_str/a_bytes] - RTuple as an original sequence is not supported yet. + e.g. (1) tuple(f(x) for x in a_list/a_tuple/a_str/a_bytes/an_rtuple) + (2) list(f(x) for x in a_list/a_tuple/a_str/a_bytes/an_rtuple) + (3) [f(x) for x in a_list/a_tuple/a_str/a_bytes/an_rtuple] Args: empty_op_llbuilder: A function that can generate an empty sequence op when @@ -230,23 +229,30 @@ def sequence_from_generator_preallocate_helper( implementation. """ if len(gen.sequences) == 1 and len(gen.indices) == 1 and len(gen.condlists[0]) == 0: - rtype = builder.node_type(gen.sequences[0]) - if is_sequence_rprimitive(rtype): - sequence = builder.accept(gen.sequences[0]) + sequence_expr = gen.sequences[0] + rtype = builder.node_type(sequence_expr) + if not (is_sequence_rprimitive(rtype) or isinstance(rtype, RTuple)): + return None + sequence = builder.accept(sequence_expr) + # For both RTuple and other sequences, get the length + if isinstance(rtype, RTuple): + # RTuple: length is number of fields + length = Integer(len(rtype.types), c_pyssize_t_rprimitive) + else: length = get_expr_length_value( - builder, gen.sequences[0], sequence, gen.line, use_pyssize_t=True + builder, sequence_expr, sequence, gen.line, use_pyssize_t=True ) - target_op = empty_op_llbuilder(length, gen.line) + target_op = empty_op_llbuilder(length, gen.line) - def set_item(item_index: Value) -> None: - e = builder.accept(gen.left_expr) - builder.call_c(set_item_op, [target_op, item_index, e], gen.line) + def set_item(item_index: Value) -> None: + e = builder.accept(gen.left_expr) + builder.call_c(set_item_op, [target_op, item_index, e], gen.line) - for_loop_helper_with_index( - builder, gen.indices[0], gen.sequences[0], sequence, set_item, gen.line, length - ) + for_loop_helper_with_index( + builder, gen.indices[0], sequence_expr, sequence, set_item, gen.line, length + ) - return target_op + return target_op return None From 4deac491d1cc2a348b520e31ffa6310e74e3f982 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 02:32:30 -0400 Subject: [PATCH 02/23] fix mypy err --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index efc64c7fc537..684fd3772fe3 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -234,7 +234,7 @@ def sequence_from_generator_preallocate_helper( if not (is_sequence_rprimitive(rtype) or isinstance(rtype, RTuple)): return None sequence = builder.accept(sequence_expr) - # For both RTuple and other sequences, get the length + length: Value if isinstance(rtype, RTuple): # RTuple: length is number of fields length = Integer(len(rtype.types), c_pyssize_t_rprimitive) From 4a6fe575032f8a5a6a887b892f5d220be0c20f09 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 02:34:22 -0400 Subject: [PATCH 03/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 684fd3772fe3..ca65a0693ff4 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -170,7 +170,7 @@ def for_loop_helper_with_index( body_insts: a function that generates the body of the loop. It needs a index as parameter. """ - assert is_sequence_rprimitive(expr_reg.type) + assert is_sequence_rprimitive(expr_reg.type) or isinstance(expr_reg.type, RTuple) target_type = builder.get_sequence_type(expr) body_block = BasicBlock() From 23e5f4a6fd4532eadef8c9ddce0d98d0a5c6a50b Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 06:55:25 +0000 Subject: [PATCH 04/23] fix: box --- mypyc/irbuild/for_helpers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index efc64c7fc537..278bc4c7559d 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -234,10 +234,11 @@ def sequence_from_generator_preallocate_helper( if not (is_sequence_rprimitive(rtype) or isinstance(rtype, RTuple)): return None sequence = builder.accept(sequence_expr) - # For both RTuple and other sequences, get the length if isinstance(rtype, RTuple): - # RTuple: length is number of fields length = Integer(len(rtype.types), c_pyssize_t_rprimitive) + # If input is RTuple, box it to tuple_rprimitive for generic iteration + # TODO: this can be optimized a bit better with an unrolled ForRTuple helper + sequence = builder.builder.box(sequence) else: length = get_expr_length_value( builder, sequence_expr, sequence, gen.line, use_pyssize_t=True @@ -835,7 +836,6 @@ def init( def gen_condition(self) -> None: builder = self.builder line = self.line - # TODO: Don't reload the length each time when iterating an immutable sequence? if self.reverse: # If we are iterating in reverse order, we obviously need # to check that the index is still positive. Somewhat less From dbaebcc6f7f738692674df644f05e1daed4d1d9c Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 02:59:52 -0400 Subject: [PATCH 05/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 99c47b4180ab..6b1ee30cfb65 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -170,7 +170,7 @@ def for_loop_helper_with_index( body_insts: a function that generates the body of the loop. It needs a index as parameter. """ - assert is_sequence_rprimitive(expr_reg.type) or isinstance(expr_reg.type, RTuple) + assert is_sequence_rprimitive(expr_reg.type) target_type = builder.get_sequence_type(expr) body_block = BasicBlock() From 7cf5a7d3ff731cacf57f6690b595a5672f51ee45 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 07:05:58 +0000 Subject: [PATCH 06/23] fix --- mypyc/irbuild/for_helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 99c47b4180ab..79b01038a2bc 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -63,6 +63,7 @@ object_rprimitive, pointer_rprimitive, short_int_rprimitive, + tuple_rprimitive, ) from mypyc.irbuild.builder import IRBuilder from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME @@ -239,7 +240,7 @@ def sequence_from_generator_preallocate_helper( length = Integer(len(rtype.types), c_pyssize_t_rprimitive) # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper - sequence = builder.builder.box(sequence) + sequence = builder.coerce(sequence, tuple_rprimitive, gen.line, force=True) else: length = get_expr_length_value( builder, sequence_expr, sequence, gen.line, use_pyssize_t=True From 19ea1df5e669f7e1ce4983f7458a0864d23b97f5 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 03:14:05 -0400 Subject: [PATCH 07/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 92b490edfb83..9365ecb55f49 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -171,7 +171,7 @@ def for_loop_helper_with_index( body_insts: a function that generates the body of the loop. It needs a index as parameter. """ - assert is_sequence_rprimitive(expr_reg.type) + assert is_sequence_rprimitive(expr_reg.type), expr_reg target_type = builder.get_sequence_type(expr) body_block = BasicBlock() From c8880ac5f8e3cdbccac39e30a6e8328ae98db3d8 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 03:16:56 -0400 Subject: [PATCH 08/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 9365ecb55f49..6042f9b0578f 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -171,7 +171,7 @@ def for_loop_helper_with_index( body_insts: a function that generates the body of the loop. It needs a index as parameter. """ - assert is_sequence_rprimitive(expr_reg.type), expr_reg + assert is_sequence_rprimitive(expr_reg.type), (expr_reg, expr_reg.type) target_type = builder.get_sequence_type(expr) body_block = BasicBlock() @@ -808,7 +808,7 @@ class ForSequence(ForGenerator): def init( self, expr_reg: Value, target_type: RType, reverse: bool, length: Value | None = None ) -> None: - assert is_sequence_rprimitive(expr_reg.type), expr_reg + assert is_sequence_rprimitive(expr_reg.type), (expr_reg, expr_reg.type) builder = self.builder # Record a Value indicating the length of the sequence, if known at compile time. self.length = length From c3cc04a1c72c8a5f66151f263f986e109a60c12b Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 03:19:52 -0400 Subject: [PATCH 09/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 6042f9b0578f..0e70d2768c28 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -241,6 +241,7 @@ def sequence_from_generator_preallocate_helper( # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper sequence = builder.coerce(sequence, tuple_rprimitive, gen.line, force=True) + assert is_tuple_rprimitive(sequence.type), sequence.type else: length = get_expr_length_value( builder, sequence_expr, sequence, gen.line, use_pyssize_t=True From 32da5b9055b400cb52f027949a9cfbb030472d14 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 07:50:41 +0000 Subject: [PATCH 10/23] fix cast tuple --- mypyc/irbuild/for_helpers.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 0e70d2768c28..2ef67a84c53f 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -230,30 +230,30 @@ def sequence_from_generator_preallocate_helper( implementation. """ if len(gen.sequences) == 1 and len(gen.indices) == 1 and len(gen.condlists[0]) == 0: + line = gen.line sequence_expr = gen.sequences[0] rtype = builder.node_type(sequence_expr) if not (is_sequence_rprimitive(rtype) or isinstance(rtype, RTuple)): return None sequence = builder.accept(sequence_expr) - length: Value + length = get_expr_length_value( + builder, sequence_expr, sequence, line, use_pyssize_t=True + ) if isinstance(rtype, RTuple): - length = Integer(len(rtype.types), c_pyssize_t_rprimitive) # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper - sequence = builder.coerce(sequence, tuple_rprimitive, gen.line, force=True) - assert is_tuple_rprimitive(sequence.type), sequence.type - else: - length = get_expr_length_value( - builder, sequence_expr, sequence, gen.line, use_pyssize_t=True - ) - target_op = empty_op_llbuilder(length, gen.line) + sequence = builder.coerce(sequence, tuple_rprimitive, line, force=True) + items = [builder.add(TupleGet(sequence, i, line) for i in range(len(rtype.types)))] + sequence = builder.new_tuple(items, line) + + target_op = empty_op_llbuilder(length, line) def set_item(item_index: Value) -> None: e = builder.accept(gen.left_expr) - builder.call_c(set_item_op, [target_op, item_index, e], gen.line) + builder.call_c(set_item_op, [target_op, item_index, e], line) for_loop_helper_with_index( - builder, gen.indices[0], sequence_expr, sequence, set_item, gen.line, length + builder, gen.indices[0], sequence_expr, sequence, set_item, line, length ) return target_op @@ -1224,6 +1224,6 @@ def get_expr_length_value( length = get_expr_length(expr) if length is None: # We cannot compute the length at compile time, so we will fetch it. - return builder.builder.builtin_len(expr_reg, line, use_pyssize_t=use_pyssize_t) + return builder.builtin_len(expr_reg, line, use_pyssize_t=use_pyssize_t) # The expression result is known at compile time, so we can use a constant. return Integer(length, c_pyssize_t_rprimitive if use_pyssize_t else short_int_rprimitive) From 78830431a6569ee3424ec6652faec1be7b431772 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 07:52:09 +0000 Subject: [PATCH 11/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/for_helpers.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 2ef67a84c53f..04db05f7c5be 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -236,16 +236,14 @@ def sequence_from_generator_preallocate_helper( if not (is_sequence_rprimitive(rtype) or isinstance(rtype, RTuple)): return None sequence = builder.accept(sequence_expr) - length = get_expr_length_value( - builder, sequence_expr, sequence, line, use_pyssize_t=True - ) + length = get_expr_length_value(builder, sequence_expr, sequence, line, use_pyssize_t=True) if isinstance(rtype, RTuple): # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper sequence = builder.coerce(sequence, tuple_rprimitive, line, force=True) items = [builder.add(TupleGet(sequence, i, line) for i in range(len(rtype.types)))] sequence = builder.new_tuple(items, line) - + target_op = empty_op_llbuilder(length, line) def set_item(item_index: Value) -> None: From c9545a139caf1b0e72406f9cd7ddb13e4678932e Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 07:57:29 +0000 Subject: [PATCH 12/23] fix attrerr --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 2ef67a84c53f..5b2faa5989de 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -1224,6 +1224,6 @@ def get_expr_length_value( length = get_expr_length(expr) if length is None: # We cannot compute the length at compile time, so we will fetch it. - return builder.builtin_len(expr_reg, line, use_pyssize_t=use_pyssize_t) + return builder.builder.builtin_len(expr_reg, line, use_pyssize_t=use_pyssize_t) # The expression result is known at compile time, so we can use a constant. return Integer(length, c_pyssize_t_rprimitive if use_pyssize_t else short_int_rprimitive) From bfe24e3b0b727c9d0b9da73c6d3048708354990c Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 08:01:46 +0000 Subject: [PATCH 13/23] fix: tuple get --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 4b5afaba44a9..ec977e3bb2ff 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -241,7 +241,7 @@ def sequence_from_generator_preallocate_helper( # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper sequence = builder.coerce(sequence, tuple_rprimitive, line, force=True) - items = [builder.add(TupleGet(sequence, i, line) for i in range(len(rtype.types)))] + items = [builder.add(TupleGet(sequence, i, line)) for i in range(len(rtype.types))] sequence = builder.new_tuple(items, line) target_op = empty_op_llbuilder(length, line) From 89a078b41595280b3973563fbd4d9778acf8ad5f Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 08:06:04 +0000 Subject: [PATCH 14/23] fix: assert --- mypyc/irbuild/for_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index ec977e3bb2ff..04d0ebbfa0c9 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -1218,7 +1218,7 @@ def get_expr_length_value( builder: IRBuilder, expr: Expression, expr_reg: Value, line: int, use_pyssize_t: bool ) -> Value: rtype = builder.node_type(expr) - assert is_sequence_rprimitive(rtype), rtype + assert is_sequence_rprimitive(rtype) or isinstance(rtype, RTuple), rtype length = get_expr_length(expr) if length is None: # We cannot compute the length at compile time, so we will fetch it. From 62fb000584346a3c8d13712aca271fcf427217a4 Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 08:09:15 +0000 Subject: [PATCH 15/23] fix: remove old line --- mypyc/irbuild/for_helpers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 04d0ebbfa0c9..11df14d0e734 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -240,7 +240,6 @@ def sequence_from_generator_preallocate_helper( if isinstance(rtype, RTuple): # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper - sequence = builder.coerce(sequence, tuple_rprimitive, line, force=True) items = [builder.add(TupleGet(sequence, i, line)) for i in range(len(rtype.types))] sequence = builder.new_tuple(items, line) From 3185c3b717a422a8a531b2c25edf38f246740c5f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 08:10:49 +0000 Subject: [PATCH 16/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/for_helpers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 11df14d0e734..6025823e8c91 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -63,7 +63,6 @@ object_rprimitive, pointer_rprimitive, short_int_rprimitive, - tuple_rprimitive, ) from mypyc.irbuild.builder import IRBuilder from mypyc.irbuild.prepare import GENERATOR_HELPER_NAME From 94ccbafac1d6cfa1e9898ff733a16d77560e596d Mon Sep 17 00:00:00 2001 From: BobTheBuidler Date: Fri, 26 Sep 2025 08:43:14 +0000 Subject: [PATCH 17/23] update ir --- mypyc/test-data/irbuild-tuple.test | 128 ++++++++++++++++++----------- 1 file changed, 78 insertions(+), 50 deletions(-) diff --git a/mypyc/test-data/irbuild-tuple.test b/mypyc/test-data/irbuild-tuple.test index 081cc1b174c9..2f52860261ba 100644 --- a/mypyc/test-data/irbuild-tuple.test +++ b/mypyc/test-data/irbuild-tuple.test @@ -691,36 +691,50 @@ L0: return r1 def test(): r0, source :: tuple[int, int, int] - r1 :: list - r2, r3, r4 :: object - r5, x :: int - r6 :: bool - r7 :: object - r8 :: i32 - r9, r10 :: bit - r11, a :: tuple + r1 :: object + r2 :: native_int + r3 :: bit + r4, r5, r6 :: int + r7, r8, r9 :: object + r10, r11 :: tuple + r12 :: native_int + r13 :: bit + r14 :: object + r15, x :: int + r16 :: bool + r17 :: object + r18 :: native_int + a :: tuple L0: r0 = (2, 4, 6) source = r0 - r1 = PyList_New(0) - r2 = box(tuple[int, int, int], source) - r3 = PyObject_GetIter(r2) + r1 = box(tuple[int, int, int], source) + r2 = PyObject_Size(r1) + r3 = r2 >= 0 :: signed + r4 = source[0] + r5 = source[1] + r6 = source[2] + r7 = box(int, r4) + r8 = box(int, r5) + r9 = box(int, r6) + r10 = PyTuple_Pack(3, r7, r8, r9) + r11 = PyTuple_New(r2) + r12 = 0 L1: - r4 = PyIter_Next(r3) - if is_error(r4) goto L4 else goto L2 + r13 = r12 < r2 :: signed + if r13 goto L2 else goto L4 :: bool L2: - r5 = unbox(int, r4) - x = r5 - r6 = f(x) - r7 = box(bool, r6) - r8 = PyList_Append(r1, r7) - r9 = r8 >= 0 :: signed + r14 = CPySequenceTuple_GetItemUnsafe(r10, r12) + r15 = unbox(int, r14) + x = r15 + r16 = f(x) + r17 = box(bool, r16) + CPySequenceTuple_SetItemUnsafe(r11, r12, r17) L3: + r18 = r12 + 1 + r12 = r18 goto L1 L4: - r10 = CPy_NoErrOccurred() -L5: - r11 = PyList_AsTuple(r1) a = r11 return 1 @@ -743,42 +757,56 @@ L0: r1 = int_eq r0, 0 return r1 def test(): - r0 :: list - r1 :: tuple[int, int, int] - r2 :: bool - r3, r4, r5 :: object - r6, x :: int - r7 :: bool - r8 :: object - r9 :: i32 - r10, r11 :: bit - r12, a :: tuple -L0: - r0 = PyList_New(0) - r1 = __main__.source :: static - if is_error(r1) goto L1 else goto L2 + r0 :: tuple[int, int, int] + r1 :: bool + r2 :: object + r3 :: native_int + r4 :: bit + r5, r6, r7 :: int + r8, r9, r10 :: object + r11, r12 :: tuple + r13 :: native_int + r14 :: bit + r15 :: object + r16, x :: int + r17 :: bool + r18 :: object + r19 :: native_int + a :: tuple +L0: + r0 = __main__.source :: static + if is_error(r0) goto L1 else goto L2 L1: - r2 = raise NameError('value for final name "source" was not set') + r1 = raise NameError('value for final name "source" was not set') unreachable L2: - r3 = box(tuple[int, int, int], r1) - r4 = PyObject_GetIter(r3) + r2 = box(tuple[int, int, int], r0) + r3 = PyObject_Size(r2) + r4 = r3 >= 0 :: signed + r5 = r0[0] + r6 = r0[1] + r7 = r0[2] + r8 = box(int, r5) + r9 = box(int, r6) + r10 = box(int, r7) + r11 = PyTuple_Pack(3, r8, r9, r10) + r12 = PyTuple_New(r3) + r13 = 0 L3: - r5 = PyIter_Next(r4) - if is_error(r5) goto L6 else goto L4 + r14 = r13 < r3 :: signed + if r14 goto L4 else goto L6 :: bool L4: - r6 = unbox(int, r5) - x = r6 - r7 = f(x) - r8 = box(bool, r7) - r9 = PyList_Append(r0, r8) - r10 = r9 >= 0 :: signed + r15 = CPySequenceTuple_GetItemUnsafe(r11, r13) + r16 = unbox(int, r15) + x = r16 + r17 = f(x) + r18 = box(bool, r17) + CPySequenceTuple_SetItemUnsafe(r12, r13, r18) L5: + r19 = r13 + 1 + r13 = r19 goto L3 L6: - r11 = CPy_NoErrOccurred() -L7: - r12 = PyList_AsTuple(r0) a = r12 return 1 From 8d7406880d7ba38c532b6f86faed6b78bea9b850 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 05:14:12 -0400 Subject: [PATCH 18/23] literals --- mypyc/irbuild/for_helpers.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 6025823e8c91..bef3ae8ab668 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -28,6 +28,7 @@ TypeAlias, Var, ) +from mypy.types import LiteralType, TupleType, get_proper_type from mypyc.ir.ops import ( ERR_NEVER, BasicBlock, @@ -36,6 +37,7 @@ IntOp, LoadAddress, LoadErrorValue, + LoadLiteral, LoadMem, MethodCall, RaiseStandardError, @@ -239,7 +241,17 @@ def sequence_from_generator_preallocate_helper( if isinstance(rtype, RTuple): # If input is RTuple, box it to tuple_rprimitive for generic iteration # TODO: this can be optimized a bit better with an unrolled ForRTuple helper - items = [builder.add(TupleGet(sequence, i, line)) for i in range(len(rtype.types))] + proper_type = get_proper_type(builder.types[sequence_expr]) + assert isinstance(proper_type, TupleType), proper_type + + items = [ + builder.add( + LoadLiteral(typ.value, object_rprimitive) + if isinstance(typ, LiteralType) and isinstance(typ.value, (int, str, bool, float)) + else TupleGet(sequence, i, line) + ) + for i, typ in enumerate(proper_type.items) + ] sequence = builder.new_tuple(items, line) target_op = empty_op_llbuilder(length, line) From 3daeecd66c7009b600232ebc46d7233f49e28a8e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:15:51 +0000 Subject: [PATCH 19/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/for_helpers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index bef3ae8ab668..77460cf5e397 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -243,11 +243,12 @@ def sequence_from_generator_preallocate_helper( # TODO: this can be optimized a bit better with an unrolled ForRTuple helper proper_type = get_proper_type(builder.types[sequence_expr]) assert isinstance(proper_type, TupleType), proper_type - + items = [ builder.add( LoadLiteral(typ.value, object_rprimitive) - if isinstance(typ, LiteralType) and isinstance(typ.value, (int, str, bool, float)) + if isinstance(typ, LiteralType) + and isinstance(typ.value, (int, str, bool, float)) else TupleGet(sequence, i, line) ) for i, typ in enumerate(proper_type.items) From 5c33f61966bc58fd5e728398f0bc277553b6842c Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 05:19:40 -0400 Subject: [PATCH 20/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 77460cf5e397..184cacd8264d 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -28,7 +28,7 @@ TypeAlias, Var, ) -from mypy.types import LiteralType, TupleType, get_proper_type +from mypy.types import LiteralType, TupleType, get_proper_type, get_proper_types from mypyc.ir.ops import ( ERR_NEVER, BasicBlock, @@ -251,7 +251,7 @@ def sequence_from_generator_preallocate_helper( and isinstance(typ.value, (int, str, bool, float)) else TupleGet(sequence, i, line) ) - for i, typ in enumerate(proper_type.items) + for i, typ in enumerate(get_proper_types(proper_type.items)) ] sequence = builder.new_tuple(items, line) From 7b572df9f53c3c4aa91a8280f7a1e3115ff11da7 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 05:25:13 -0400 Subject: [PATCH 21/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 184cacd8264d..4a9a55e2a475 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -248,7 +248,6 @@ def sequence_from_generator_preallocate_helper( builder.add( LoadLiteral(typ.value, object_rprimitive) if isinstance(typ, LiteralType) - and isinstance(typ.value, (int, str, bool, float)) else TupleGet(sequence, i, line) ) for i, typ in enumerate(get_proper_types(proper_type.items)) From a411eb1b75210c46f60fbbd864c43176be560214 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Fri, 26 Sep 2025 05:48:37 -0400 Subject: [PATCH 22/23] Update for_helpers.py --- mypyc/irbuild/for_helpers.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 4a9a55e2a475..5413f283b4c2 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -244,14 +244,11 @@ def sequence_from_generator_preallocate_helper( proper_type = get_proper_type(builder.types[sequence_expr]) assert isinstance(proper_type, TupleType), proper_type - items = [ - builder.add( - LoadLiteral(typ.value, object_rprimitive) - if isinstance(typ, LiteralType) - else TupleGet(sequence, i, line) - ) + get_item_ops = [ + LoadLiteral(typ.value, object_rprimitive) if isinstance(typ, LiteralType) else TupleGet(sequence, i, line) for i, typ in enumerate(get_proper_types(proper_type.items)) ] + items = list(map(builder.add, get_item_ops)) sequence = builder.new_tuple(items, line) target_op = empty_op_llbuilder(length, line) From 29ac607a93fafa6e748d2a515ac0de34f21a8654 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 09:50:19 +0000 Subject: [PATCH 23/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypyc/irbuild/for_helpers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mypyc/irbuild/for_helpers.py b/mypyc/irbuild/for_helpers.py index 5413f283b4c2..89ae3c772d75 100644 --- a/mypyc/irbuild/for_helpers.py +++ b/mypyc/irbuild/for_helpers.py @@ -245,7 +245,11 @@ def sequence_from_generator_preallocate_helper( assert isinstance(proper_type, TupleType), proper_type get_item_ops = [ - LoadLiteral(typ.value, object_rprimitive) if isinstance(typ, LiteralType) else TupleGet(sequence, i, line) + ( + LoadLiteral(typ.value, object_rprimitive) + if isinstance(typ, LiteralType) + else TupleGet(sequence, i, line) + ) for i, typ in enumerate(get_proper_types(proper_type.items)) ] items = list(map(builder.add, get_item_ops))