Commit 5ccc9e46 authored by Stefan Behnel's avatar Stefan Behnel

Allow for-in-range loop targets to be arbitrary expressions, not just plain names.

Closes #1831.
parent c1fb0be3
...@@ -53,6 +53,9 @@ Bugs fixed ...@@ -53,6 +53,9 @@ Bugs fixed
* abs(signed int) now returns a signed rather than unsigned int. * abs(signed int) now returns a signed rather than unsigned int.
(Github issue #1837) (Github issue #1837)
* Compilation failed if the for-in-range loop target was not a variable but a more
complex expression, e.g. an item assignment. (Github issue #1831)
* Compile time evaluations of (partially) constant f-strings could show incorrect * Compile time evaluations of (partially) constant f-strings could show incorrect
results. results.
......
...@@ -6456,16 +6456,20 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -6456,16 +6456,20 @@ class ForFromStatNode(LoopNode, StatNode):
self.bound1.result(), offset, self.bound1.result(), offset,
loopvar_name, self.relation2, self.bound2.result(), loopvar_name, self.relation2, self.bound2.result(),
loopvar_name, incop)) loopvar_name, incop))
if self.py_loopvar_node:
self.py_loopvar_node.generate_evaluation_code(code) coerced_loopvar_node = self.py_loopvar_node
self.target.generate_assignment_code(self.py_loopvar_node, code) if coerced_loopvar_node is None and from_range:
elif from_range: loopvar_cvalue = loopvar_name
code.putln("%s = %s%s;" % ( if self.target.type.is_enum:
self.target.result(), loopvar_cvalue = '(%s)%s' % (self.target.type.declaration_code(''), loopvar_cvalue)
'(%s)' % self.target.type.declaration_code('') if self.target.type.is_enum else '', coerced_loopvar_node = ExprNodes.RawCNameExprNode(self.target.pos, loopvar_type, loopvar_cvalue)
loopvar_name)) if coerced_loopvar_node is not None:
coerced_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(coerced_loopvar_node, code)
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
code.put_label(code.continue_label) code.put_label(code.continue_label)
if self.py_loopvar_node: if self.py_loopvar_node:
# This mess is to make for..from loops with python targets behave # This mess is to make for..from loops with python targets behave
# exactly like those with C targets with regards to re-assignment # exactly like those with C targets with regards to re-assignment
...@@ -6498,7 +6502,9 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -6498,7 +6502,9 @@ class ForFromStatNode(LoopNode, StatNode):
if self.target.entry.is_pyglobal: if self.target.entry.is_pyglobal:
code.put_decref(target_node.result(), target_node.type) code.put_decref(target_node.result(), target_node.type)
target_node.release(code) target_node.release(code)
code.putln("}") code.putln("}")
if self.py_loopvar_node: if self.py_loopvar_node:
# This is potentially wasteful, but we don't want the semantics to # This is potentially wasteful, but we don't want the semantics to
# depend on whether or not the loop is a python type. # depend on whether or not the loop is a python type.
...@@ -6506,6 +6512,7 @@ class ForFromStatNode(LoopNode, StatNode): ...@@ -6506,6 +6512,7 @@ class ForFromStatNode(LoopNode, StatNode):
self.target.generate_assignment_code(self.py_loopvar_node, code) self.target.generate_assignment_code(self.py_loopvar_node, code)
if from_range: if from_range:
code.funcstate.release_temp(loopvar_name) code.funcstate.release_temp(loopvar_name)
break_label = code.break_label break_label = code.break_label
code.set_loop_labels(old_loop_labels) code.set_loop_labels(old_loop_labels)
if self.else_clause: if self.else_clause:
......
...@@ -14,6 +14,23 @@ cdef int* f(int x[2][2]): ...@@ -14,6 +14,23 @@ cdef int* f(int x[2][2]):
return x[0] return x[0]
def assign_index_in_loop():
"""
>>> assign_index_in_loop()
2
"""
cdef int i = 0
cdef int[1] a
cdef int[1] b
for a[0], b[0] in enumerate(range(3)):
assert a[0] == b[0]
assert a[0] == i
i += 1
assert a[0] == b[0]
return b[0]
def test2(): def test2():
""" """
>>> test2() >>> test2()
......
...@@ -62,3 +62,22 @@ def test_g(): ...@@ -62,3 +62,22 @@ def test_g():
cdef Grail l cdef Grail l
spam.g = &l spam.g = &l
eggs_g(spam) eggs_g(spam)
cdef struct Ints:
int a, b
def assign_fields_in_loop():
"""
>>> assign_fields_in_loop()
2
"""
cdef int i = 0
cdef Ints s
for s.a, s.b in enumerate(range(3)):
assert s.a == s.b
assert s.a == i
i += 1
assert s.a == s.b
return s.b
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