summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2018-12-14 11:34:21 +0100
committerStefan Behnel <stefan_ml@behnel.de>2018-12-14 11:34:21 +0100
commitc9682a3e9a018f9867116578c23afe74942a7142 (patch)
tree6405163340b3a6f52f5094fd190d470e9384cd04
parent2a85b461d951545367d911b08a8bf00d2cd53cc6 (diff)
downloadcython-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.py9
-rw-r--r--tests/run/for_in_iter.py31
-rw-r--r--tests/run/tuple_constants.pyx30
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]")