Commit c9682a3e authored by Stefan Behnel's avatar Stefan Behnel

Prevent dynamically multiplied tuple constants from being deduplicated. Only...

Prevent dynamically multiplied tuple constants from being deduplicated. Only the constant part is considered for them.
parent 2a85b461
...@@ -199,10 +199,11 @@ def make_dedup_key(outer_type, item_nodes): ...@@ -199,10 +199,11 @@ def make_dedup_key(outer_type, item_nodes):
""" """
item_keys = [ item_keys = [
(py_object_type, None) if node is None (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 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 (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 for node in item_nodes
] ]
if None in item_keys: if None in item_keys:
...@@ -7989,7 +7990,9 @@ class TupleNode(SequenceNode): ...@@ -7989,7 +7990,9 @@ class TupleNode(SequenceNode):
return return
if self.is_literal or self.is_partly_literal: 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) 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) const_code = code.get_cached_constants_writer(tuple_target)
if const_code is not None: if const_code is not None:
......
...@@ -61,6 +61,37 @@ def for_in_literal_mult_list(): ...@@ -61,6 +61,37 @@ def for_in_literal_mult_list():
l.append(i) l.append(i)
return l 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): class Iterable(object):
""" """
>>> for_in_pyiter(Iterable(5)) >>> for_in_pyiter(Iterable(5))
......
...@@ -46,9 +46,9 @@ def return_folded_tuple(): ...@@ -46,9 +46,9 @@ def return_folded_tuple():
def return_nested_tuple(): def return_nested_tuple():
""" """
>>> 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", @cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]") "//TupleNode[@is_literal = true]")
...@@ -71,6 +71,32 @@ def return_constant_tuple2(): ...@@ -71,6 +71,32 @@ def return_constant_tuple2():
""" """
return (1,2) 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", @cython.test_assert_path_exists("//TupleNode",
"//TupleNode[@is_literal = true]") "//TupleNode[@is_literal = true]")
@cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]") @cython.test_fail_if_path_exists("//TupleNode[@is_literal = false]")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment