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
* abs(signed int) now returns a signed rather than unsigned int.
(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
results.
......
......@@ -6456,16 +6456,20 @@ class ForFromStatNode(LoopNode, StatNode):
self.bound1.result(), offset,
loopvar_name, self.relation2, self.bound2.result(),
loopvar_name, incop))
if self.py_loopvar_node:
self.py_loopvar_node.generate_evaluation_code(code)
self.target.generate_assignment_code(self.py_loopvar_node, code)
elif from_range:
code.putln("%s = %s%s;" % (
self.target.result(),
'(%s)' % self.target.type.declaration_code('') if self.target.type.is_enum else '',
loopvar_name))
coerced_loopvar_node = self.py_loopvar_node
if coerced_loopvar_node is None and from_range:
loopvar_cvalue = loopvar_name
if self.target.type.is_enum:
loopvar_cvalue = '(%s)%s' % (self.target.type.declaration_code(''), loopvar_cvalue)
coerced_loopvar_node = ExprNodes.RawCNameExprNode(self.target.pos, loopvar_type, loopvar_cvalue)
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)
code.put_label(code.continue_label)
if self.py_loopvar_node:
# This mess is to make for..from loops with python targets behave
# exactly like those with C targets with regards to re-assignment
......@@ -6498,7 +6502,9 @@ class ForFromStatNode(LoopNode, StatNode):
if self.target.entry.is_pyglobal:
code.put_decref(target_node.result(), target_node.type)
target_node.release(code)
code.putln("}")
if self.py_loopvar_node:
# This is potentially wasteful, but we don't want the semantics to
# depend on whether or not the loop is a python type.
......@@ -6506,6 +6512,7 @@ class ForFromStatNode(LoopNode, StatNode):
self.target.generate_assignment_code(self.py_loopvar_node, code)
if from_range:
code.funcstate.release_temp(loopvar_name)
break_label = code.break_label
code.set_loop_labels(old_loop_labels)
if self.else_clause:
......
......@@ -14,6 +14,23 @@ cdef int* f(int x[2][2]):
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():
"""
>>> test2()
......
......@@ -62,3 +62,22 @@ def test_g():
cdef Grail l
spam.g = &l
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