Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b9bfa49

Browse files
committed
fix compiler crash for generator expressions with a constant False condition
--HG-- extra : transplant_source : C%C7%2Ak%C4%89%DA%C1f%85%86%0D%9E%7F_%B4%17%D2t%40
1 parent b640de6 commit b9bfa49

3 files changed

Lines changed: 103 additions & 0 deletions

File tree

Cython/Compiler/Optimize.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3117,11 +3117,30 @@ def visit_IfStatNode(self, node):
31173117
break
31183118
else:
31193119
assert condition_result == False
3120+
# prevent killing generators, but simplify them as much as possible
3121+
yield_expr = self._find_genexpr_yield(if_clause.body)
3122+
if yield_expr is not None:
3123+
if_clause.condition = ExprNodes.BoolNode(if_clause.condition.pos, value=False)
3124+
yield_expr.arg = ExprNodes.NoneNode(yield_expr.arg.pos)
3125+
if_clauses.append(if_clause)
3126+
else:
3127+
# False clauses outside of generators can safely be deleted
3128+
pass
31203129
if not if_clauses:
31213130
return node.else_clause
31223131
node.if_clauses = if_clauses
31233132
return node
31243133

3134+
def _find_genexpr_yield(self, node):
3135+
body_node_types = (Nodes.ForInStatNode, Nodes.IfStatNode)
3136+
while isinstance(node, body_node_types):
3137+
node = node.body
3138+
if isinstance(node, Nodes.ExprStatNode):
3139+
node = node.expr
3140+
if isinstance(node, ExprNodes.YieldExprNode):
3141+
return node
3142+
return None
3143+
31253144
# in the future, other nodes can have their own handler method here
31263145
# that can replace them with a constant result node
31273146

tests/run/generator_expressions.pyx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ def genexpr_if():
2121
assert x == 'abc' # don't leak
2222
return result
2323

24+
def genexpr_if_false():
25+
"""
26+
>>> genexpr_if_false()
27+
[]
28+
"""
29+
x = 'abc'
30+
result = list( x*2 for x in range(5) if False )
31+
assert x == 'abc' # don't leak
32+
return result
33+
2434
def genexpr_with_lambda():
2535
"""
2636
>>> genexpr_with_lambda()
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# mode: run
2+
# cython: language_level=3
3+
4+
"""
5+
Adapted from CPython's test_grammar.py
6+
"""
7+
8+
def genexpr_simple():
9+
"""
10+
>>> sum([ x**2 for x in range(10) ])
11+
285
12+
>>> sum(genexpr_simple())
13+
285
14+
"""
15+
return (x**2 for x in range(10))
16+
17+
def genexpr_conditional():
18+
"""
19+
>>> sum([ x*x for x in range(10) if x%2 ])
20+
165
21+
>>> sum(genexpr_conditional())
22+
165
23+
"""
24+
return (x*x for x in range(10) if x%2)
25+
26+
def genexpr_nested2():
27+
"""
28+
>>> sum([x for x in range(10)])
29+
45
30+
>>> sum(genexpr_nested2())
31+
45
32+
"""
33+
return (x for x in (y for y in range(10)))
34+
35+
def genexpr_nested3():
36+
"""
37+
>>> sum([x for x in range(10)])
38+
45
39+
>>> sum(genexpr_nested3())
40+
45
41+
"""
42+
return (x for x in (y for y in (z for z in range(10))))
43+
44+
def genexpr_nested_listcomp():
45+
"""
46+
>>> sum([x for x in range(10)])
47+
45
48+
>>> sum(genexpr_nested_listcomp())
49+
45
50+
"""
51+
return (x for x in [y for y in (z for z in range(10))])
52+
53+
def genexpr_nested_conditional():
54+
"""
55+
>>> sum([ x for x in [y for y in [z for z in range(10) if True]] if True ])
56+
45
57+
>>> sum(genexpr_nested_conditional())
58+
45
59+
"""
60+
return (x for x in (y for y in (z for z in range(10) if True)) if True)
61+
62+
def genexpr_nested2_conditional_empty():
63+
"""
64+
>>> sum(genexpr_nested2_conditional_empty())
65+
0
66+
"""
67+
return (y for y in (z for z in range(10) if True) if False)
68+
69+
def genexpr_nested3_conditional_empty():
70+
"""
71+
>>> sum(genexpr_nested3_conditional_empty())
72+
0
73+
"""
74+
return (x for x in (y for y in (z for z in range(10) if True) if False) if True)

0 commit comments

Comments
 (0)