summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2016-03-24 20:59:36 +0100
committerStefan Behnel <stefan_ml@behnel.de>2016-03-24 20:59:36 +0100
commitdca035a35678c68fd804769dc6c83effa6172de1 (patch)
tree5dfeb181875277e2e3a8245df209e4839eff7966
parent9c7dac3bdda2fbae69a06eae5ca7791bf8144bdd (diff)
downloadcython-dca035a35678c68fd804769dc6c83effa6172de1.tar.gz
remove dead left-over code in any()/all() optimisation that issued an "unreachable code" warning
-rw-r--r--CHANGES.rst3
-rw-r--r--Cython/Compiler/Optimize.py25
-rw-r--r--tests/run/all.pyx17
-rw-r--r--tests/run/control_flow_loop.pyx55
4 files changed, 79 insertions, 21 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 1ef048fb3..e0bd6c25b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -59,6 +59,9 @@ Bugs fixed
* Iteration over ``dict(...).items()`` failed to get optimised when dict
arguments included keyword arguments.
+* Optimised `all(genexpr)`/`any(genexpr)` calls could warn about unused code.
+ This fixes ticket 876.
+
0.23.5 (2016-03-26)
===================
diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py
index d7f3e772e..95b388097 100644
--- a/Cython/Compiler/Optimize.py
+++ b/Cython/Compiler/Optimize.py
@@ -1526,13 +1526,9 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
for L in LL:
for x in L:
if not p(x):
- _result = False
- break
- else:
- continue
- break
+ return False
else:
- _result = True
+ return True
"""
return self._transform_any_all(node, pos_args, False)
@@ -1546,13 +1542,9 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
for L in LL:
for x in L:
if p(x):
- _result = True
- break
- else:
- continue
- break
+ return True
else:
- _result = False
+ return False
"""
return self._transform_any_all(node, pos_args, True)
@@ -1583,15 +1575,6 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
value=ExprNodes.BoolNode(yield_expression.pos, value=is_any, constant_result=is_any))
)]
)
- loop = loop_node
- while isinstance(loop.body, Nodes.LoopNode):
- next_loop = loop.body
- loop.body = Nodes.StatListNode(loop.body.pos, stats=[
- loop.body,
- Nodes.BreakStatNode(yield_expression.pos)
- ])
- next_loop.else_clause = Nodes.ContinueStatNode(yield_expression.pos)
- loop = next_loop
loop_node.else_clause = Nodes.ReturnStatNode(
node.pos,
value=ExprNodes.BoolNode(yield_expression.pos, value=not is_any, constant_result=not is_any))
diff --git a/tests/run/all.pyx b/tests/run/all.pyx
index a5fcda4a9..a9c7f5002 100644
--- a/tests/run/all.pyx
+++ b/tests/run/all.pyx
@@ -1,3 +1,5 @@
+# mode: run
+# tag: all, builtins, werror
cdef class VerboseGetItem(object):
cdef object sequence
@@ -53,6 +55,7 @@ def all_item(x):
"""
return all(x)
+
@cython.test_assert_path_exists(
"//ForInStatNode",
"//InlinedGeneratorExpressionNode"
@@ -86,6 +89,7 @@ def all_in_simple_gen(seq):
"""
return all(x for x in seq)
+
@cython.test_assert_path_exists(
"//ForInStatNode",
"//InlinedGeneratorExpressionNode"
@@ -122,6 +126,7 @@ def all_in_simple_gen_scope(seq):
assert x == 'abc'
return result
+
@cython.test_assert_path_exists(
"//ForInStatNode",
"//InlinedGeneratorExpressionNode"
@@ -158,10 +163,12 @@ def all_in_conditional_gen(seq):
"""
return all(x%3 for x in seq if x%2 == 1)
+
mixed_ustring = u'AbcDefGhIjKlmnoP'
lower_ustring = mixed_ustring.lower()
upper_ustring = mixed_ustring.upper()
+
@cython.test_assert_path_exists(
'//PythonCapiCallNode',
'//ForFromStatNode'
@@ -181,6 +188,7 @@ def all_lower_case_characters(unicode ustring):
"""
return all(uchar.islower() for uchar in ustring)
+
@cython.test_assert_path_exists(
"//ForInStatNode",
"//InlinedGeneratorExpressionNode",
@@ -217,6 +225,7 @@ def all_in_typed_gen(seq):
cdef int x
return all(x for x in seq)
+
@cython.test_assert_path_exists(
"//ForInStatNode",
"//InlinedGeneratorExpressionNode",
@@ -268,6 +277,14 @@ def all_in_double_gen(seq):
1
2
False
+ >>> all_in_double_gen([VerboseGetItem([1,1,1]),VerboseGetItem([1,0,1]),VerboseGetItem([1,1])])
+ 0
+ 1
+ 2
+ 3
+ 0
+ 1
+ False
"""
cdef int x
return all(x for L in seq for x in L)
diff --git a/tests/run/control_flow_loop.pyx b/tests/run/control_flow_loop.pyx
new file mode 100644
index 000000000..6581f6ee3
--- /dev/null
+++ b/tests/run/control_flow_loop.pyx
@@ -0,0 +1,55 @@
+# mode: run
+# tag: forin, control-flow, werror
+
+def for_in_break(LL, p=bool):
+ """
+ >>> for_in_break([[1,2,3], [4,5,6]])
+ True
+ >>> for_in_break([[1,2,3], [4,5,0]])
+ False
+ >>> for_in_break([[1,2,3], [0,4,5]])
+ False
+ >>> for_in_break([[1,2,3], [0,4,5], [6,7,8]])
+ False
+
+ >>> def collect(x):
+ ... v.append(x)
+ ... return x
+
+ >>> v = []
+ >>> for_in_break([[1,2,3], [4,5,6]], p=collect)
+ True
+ >>> v
+ [1, 2, 3, 4, 5, 6]
+
+ >>> v = []
+ >>> for_in_break([[1,2,3], [4,5,0]], p=collect)
+ False
+ >>> v
+ [1, 2, 3, 4, 5, 0]
+
+ >>> v = []
+ >>> for_in_break([[1,2,3], [0,4,5]], p=collect)
+ False
+ >>> v
+ [1, 2, 3, 0]
+
+ >>> v = []
+ >>> for_in_break([[1,2,3], [0,4,5], [6,7,8]], p=collect)
+ False
+ >>> v
+ [1, 2, 3, 0]
+ """
+ result = 'NOK'
+ # implements the builtin all()
+ for L in LL:
+ for x in L:
+ if not p(x):
+ result = False
+ break
+ else:
+ continue
+ break
+ else:
+ result = True
+ return result