Commit d8b19074 authored by Stefan Behnel's avatar Stefan Behnel

drop C array unpacking back into C instead of going back and forth through Python list coercion

parent 3ae163a6
...@@ -4830,19 +4830,16 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -4830,19 +4830,16 @@ class SingleAssignmentNode(AssignmentNode):
def unroll(self, node, target_size, env): def unroll(self, node, target_size, env):
from . import ExprNodes, UtilNodes from . import ExprNodes, UtilNodes
base = node
start_node = stop_node = step_node = check_node = None
if node.type.is_ctuple: if node.type.is_ctuple:
if node.type.size == target_size: slice_size = node.type.size
base = node
start_node = None
stop_node = None
step_node = None
check_node = None
else:
error(self.pos, "Unpacking type %s requires exactly %s arguments." % (
node.type, node.type.size))
return
elif node.type.is_ptr: elif node.type.is_ptr or node.type.is_array:
while isinstance(node, ExprNodes.SliceIndexNode) and not (node.start or node.stop):
base = node = node.base
if isinstance(node, ExprNodes.SliceIndexNode): if isinstance(node, ExprNodes.SliceIndexNode):
base = node.base base = node.base
start_node = node.start start_node = node.start
...@@ -4875,19 +4872,25 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -4875,19 +4872,25 @@ class SingleAssignmentNode(AssignmentNode):
try: try:
slice_size = (get_const(stop_node, None) - get_const(start_node, 0)) / get_const(step_node, 1) slice_size = (get_const(stop_node, None) - get_const(start_node, 0)) / get_const(step_node, 1)
if target_size != slice_size:
error(self.pos, "Assignment to/from slice of wrong length, expected %d, got %d" % (
slice_size, target_size))
except ValueError: except ValueError:
error(self.pos, "C array assignment currently requires known endpoints") error(self.pos, "C array assignment currently requires known endpoints")
return return
check_node = None
elif node.type.is_array:
slice_size = node.type.size
if not isinstance(slice_size, (int, long)):
return # might still work when coercing to Python
else: else:
return return
else: else:
return return
if slice_size != target_size:
error(self.pos, "Assignment to/from slice of wrong length, expected %s, got %s" % (
slice_size, target_size))
return
items = [] items = []
base = UtilNodes.LetRefNode(base) base = UtilNodes.LetRefNode(base)
refs = [base] refs = [base]
......
...@@ -162,7 +162,12 @@ def test_starred_from_array(): ...@@ -162,7 +162,12 @@ def test_starred_from_array():
return x, y, z return x, y, z
@cython.test_fail_if_path_exists(
'//ParallelAssignmentNode//CoerceToPyTypeNode',
'//ParallelAssignmentNode//CoerceFromPyTypeNode',
)
@cython.test_assert_path_exists( @cython.test_assert_path_exists(
'//ParallelAssignmentNode',
'//ReturnStatNode//CoerceToPyTypeNode' '//ReturnStatNode//CoerceToPyTypeNode'
) )
def test_multiple_from_array(): def test_multiple_from_array():
...@@ -170,7 +175,6 @@ def test_multiple_from_array(): ...@@ -170,7 +175,6 @@ def test_multiple_from_array():
>>> test_multiple_from_array() >>> test_multiple_from_array()
(1, 2, 3) (1, 2, 3)
""" """
# FIXME: copy currently goes through a Python list, even though we infer the right target types
cdef int[3] a cdef int[3] a
a[0] = 1 a[0] = 1
a[1] = 2 a[1] = 2
...@@ -179,6 +183,26 @@ def test_multiple_from_array(): ...@@ -179,6 +183,26 @@ def test_multiple_from_array():
return x, y, z return x, y, z
@cython.test_fail_if_path_exists(
'//ParallelAssignmentNode//CoerceToPyTypeNode'
)
@cython.test_assert_path_exists(
'//ParallelAssignmentNode',
'//ReturnStatNode//CoerceToPyTypeNode'
)
def test_multiple_from_array_full_slice():
"""
>>> test_multiple_from_array_full_slice()
(1, 2, 3)
"""
cdef int[3] a
a[0] = 1
a[1] = 2
a[2] = 3
x, y, z = a[:]
return x, y, z
@cython.test_fail_if_path_exists( @cython.test_fail_if_path_exists(
'//ParallelAssignmentNode//CoerceToPyTypeNode' '//ParallelAssignmentNode//CoerceToPyTypeNode'
) )
......
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