diff options
author | Stefan Behnel <stefan_ml@behnel.de> | 2018-12-14 11:34:21 +0100 |
---|---|---|
committer | Stefan Behnel <stefan_ml@behnel.de> | 2018-12-14 11:34:21 +0100 |
commit | c9682a3e9a018f9867116578c23afe74942a7142 (patch) | |
tree | 6405163340b3a6f52f5094fd190d470e9384cd04 | |
parent | 2a85b461d951545367d911b08a8bf00d2cd53cc6 (diff) | |
download | cython-c9682a3e9a018f9867116578c23afe74942a7142.tar.gz |
Prevent dynamically multiplied tuple constants from being deduplicated. Only the constant part is considered for them.
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 9 | ||||
-rw-r--r-- | tests/run/for_in_iter.py | 31 | ||||
-rw-r--r-- | tests/run/tuple_constants.pyx | 30 |
3 files changed, 65 insertions, 5 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index e5a63d8f6..1679c1793 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -199,10 +199,11 @@ def make_dedup_key(outer_type, item_nodes): """ item_keys = [ (py_object_type, None) if node is None - else make_dedup_key(node.type, node.args) if node.is_sequence_constructor + # For sequences and their "mult_factor", see TupleNode. + else make_dedup_key(node.type, [node.mult_factor if node.is_literal else None] + node.args) if node.is_sequence_constructor else make_dedup_key(node.type, (node.start, node.stop, node.step)) if node.is_slice else (node.type, node.constant_result) if node.has_constant_result() - else None + else None # something we cannot handle => short-circuit below for node in item_nodes ] if None in item_keys: @@ -7989,7 +7990,9 @@ class TupleNode(SequenceNode): return if self.is_literal or self.is_partly_literal: - dedup_key = make_dedup_key(self.type, self.args) if self.is_literal else None + # The "mult_factor" is part of the deduplication if it is also constant, i.e. when + # we deduplicate the multiplied result. Otherwise, only deduplicate the constant part. + dedup_key = make_dedup_key(self.type, [self.mult_factor if self.is_literal else None] + self.args) tuple_target = code.get_py_const(py_object_type, 'tuple', cleanup_level=2, dedup_key=dedup_key) const_code = code.get_cached_constants_writer(tuple_target) if const_code is not None: diff --git a/tests/run/for_in_iter.py b/tests/run/for_in_iter.py index f41ed18d2..1b86de2a3 100644 --- a/tests/run/for_in_iter.py +++ b/tests/run/for_in_iter.py @@ -61,6 +61,37 @@ def for_in_literal_mult_list(): l.append(i) return l + +def listcomp_over_multiplied_constant_tuple(): + """ + >>> listcomp_over_multiplied_constant_tuple() + [[], [1, 2, 3], [1, 2, 3, 1, 2, 3], [1, 2, 3, 1, 2, 3, 1, 2, 3], [1, 2, 3, 1, 2, 3]] + """ + return [ + [i for i in (1, 2, 3) * 0], + [i for i in (1, 2, 3) * 1], + [i for i in (1, 2, 3) * 2], + [i for i in (1, 2, 3) * 3], + [i for i in (1, 2, 3) * 2], + ] + + +@cython.test_assert_path_exists('//ReturnStatNode//ForInStatNode//TupleNode') +@cython.test_fail_if_path_exists('//ReturnStatNode//ForInStatNode//ListNode') +def listcomp_over_multiplied_constant_list(): + """ + >>> listcomp_over_multiplied_constant_list() + [[], [1, 2, 3], [1, 2, 3, 1, 2, 3], [1, 2, 3, 1, 2, 3, 1, 2, 3], [1, 2, 3, 1, 2, 3]] + """ + return [ + [i for i in [1, 2, 3] * 0], + [i for i in [1, 2, 3] * 1], + [i for i in [1, 2, 3] * 2], + [i for i in [1, 2, 3] * 3], + [i for i in [1, 2, 3] * 2], + ] + + class Iterable(object): """ >>> for_in_pyiter(Iterable(5)) diff --git a/tests/run/tuple_constants.pyx b/tests/run/tuple_constants.pyx index 99829f8f1..ee9be342a 100644 --- a/tests/run/tuple_constants.pyx +++ b/tests/run/tuple_constants.pyx @@ -46,9 +46,9 @@ def return_folded_tuple(): def return_nested_tuple(): """ >>> return_nested_tuple() - (1, (2, 3), (3, (4, 5))) + (1, (2, 3), (3, (4, 5), (2, 3, 2, 3))) """ - return (1, (2, 3), (3, (4, 5))) + return (1, (2, 3), (3, (4, 5), (2, 3) * 2)) @cython.test_assert_path_exists("//TupleNode", "//TupleNode[@is_literal = true]") @@ -71,6 +71,32 @@ def return_constant_tuple2(): """ return (1,2) + +def return_multiplied_constant_tuple(n): + """ + >>> tuples = return_multiplied_constant_tuple(2) + >>> type(tuples) is tuple + True + >>> for t in tuples: print(t) + () + (1, 2, 3) + (1, 2, 3, 1, 2, 3) + (1, 2, 3, 1, 2, 3, 1, 2, 3) + (1, 2, 3, 1, 2, 3) + (1, 2, 3, 1, 2, 3) + ((1, 2, 3, 1, 2, 3), (1, 2, 3), (1, 2, 3, 1, 2, 3)) + """ + return ( + (1, 2, 3) * 0, + (1, 2, 3) * 1, + (1, 2, 3) * 2, + (1, 2, 3) * 3, + (1, 2, 3) * 2, + (1, 2, 3) * n, + ((1, 2, 3) * n, (1, 2, 3), (1, 2, 3) * n), + ) + + @cython.test_assert_path_exists("//TupleNode", "//TupleNode[@is_literal = true]") @cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]") |