Commit 5e08f83c authored by Stefan Behnel's avatar Stefan Behnel Committed by Robert Bradshaw

fix repeated list multiplication

--HG--
extra : amend_source : 2797e0ad678cc0a33a2548a8a20b00475bc8a21b

Conflicts:
	CHANGES.rst
parent 061ca113
...@@ -2,6 +2,36 @@ ...@@ -2,6 +2,36 @@
Cython Changelog Cython Changelog
================ ================
=======
Latest
=======
Features added
--------------
Bugs fixed
----------
* List/Tuple literals multiplied by more than one factor were only multiplied
by the last factor instead of all.
* In-place assignments to variables with inferred Python builtin/extension
types could fail with type errors if the result value type was incompatible
with the type of the previous value.
* The C code generation order of cdef classes, closures, helper code,
etc. was not deterministic, thus leading to high code churn.
* Type inference could fail to deduce C enum types.
* Type inference could deduce unsafe or inefficient types from integer
assignments within a mix of inferred Python variables and integer
variables.
Other changes
-------------
0.20 (2014-01-18) 0.20 (2014-01-18)
================= =================
......
...@@ -3375,19 +3375,30 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): ...@@ -3375,19 +3375,30 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
def visit_MulNode(self, node): def visit_MulNode(self, node):
self._calculate_const(node) self._calculate_const(node)
if isinstance(node.operand1, (ExprNodes.ListNode, ExprNodes.TupleNode)): if node.operand1.is_sequence_constructor:
return self._calculate_constant_seq(node.operand1, node.operand2) return self._calculate_constant_seq(node, node.operand1, node.operand2)
if isinstance(node.operand1, ExprNodes.IntNode) and \ if isinstance(node.operand1, ExprNodes.IntNode) and \
isinstance(node.operand2, (ExprNodes.ListNode, ExprNodes.TupleNode)): node.operand2.is_sequence_constructor:
return self._calculate_constant_seq(node.operand2, node.operand1) return self._calculate_constant_seq(node, node.operand2, node.operand1)
return self.visit_BinopNode(node) return self.visit_BinopNode(node)
def _calculate_constant_seq(self, sequence_node, factor): def _calculate_constant_seq(self, node, sequence_node, factor):
if factor.constant_result != 1 and sequence_node.args: if factor.constant_result != 1 and sequence_node.args:
if isinstance(factor.constant_result, (int, long)) and factor.constant_result <= 0: if isinstance(factor.constant_result, (int, long)) and factor.constant_result <= 0:
del sequence_node.args[:] del sequence_node.args[:]
factor = None sequence_node.mult_factor = None
sequence_node.mult_factor = factor elif sequence_node.mult_factor is not None:
if (isinstance(factor.constant_result, (int, long)) and
isinstance(sequence_node.mult_factor.constant_result, (int, long))):
value = sequence_node.mult_factor.constant_result * factor.constant_result
sequence_node.mult_factor = ExprNodes.IntNode(
sequence_node.mult_factor.pos,
value=str(value), constant_result=value)
else:
# don't know if we can combine the factors, so don't
return self.visit_BinopNode(node)
else:
sequence_node.mult_factor = factor
return sequence_node return sequence_node
def visit_PrimaryCmpNode(self, node): def visit_PrimaryCmpNode(self, node):
......
...@@ -291,6 +291,28 @@ def mult_empty_list(): ...@@ -291,6 +291,28 @@ def mult_empty_list():
return 5 * [] * 100 return 5 * [] * 100
@cython.test_fail_if_path_exists(
"//MulNode",
)
def mult_list_int_int():
"""
>>> mult_list_int_int()
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
"""
return [1, 2] * 2 * 3
@cython.test_fail_if_path_exists(
"//MulNode",
)
def mult_int_list_int():
"""
>>> mult_int_list_int()
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
"""
return 3 * [1, 2] * 2
@cython.test_fail_if_path_exists( @cython.test_fail_if_path_exists(
"//MulNode", "//MulNode",
"//ListNode//IntNode", "//ListNode//IntNode",
......
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