From 469db401866e6c78d20309e36a28edaf6ac178be Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Mon, 11 Mar 2013 11:00:02 +0100 Subject: [PATCH] strip down for-in-loops with empty iterables --- Cython/Compiler/Optimize.py | 9 +++++- tests/run/constant_folding.py | 68 +++++++++++++++++++++++++++++++++++++++ tests/run/constant_folding_cy.pyx | 17 ++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py index 3ea542f..a68dc67 100644 --- a/Cython/Compiler/Optimize.py +++ b/Cython/Compiler/Optimize.py @@ -3235,8 +3235,15 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations): def visit_ForInStatNode(self, node): self.visitchildren(node) - # iterating over a list literal? => tuples are more efficient sequence = node.iterator.sequence + if isinstance(sequence, ExprNodes.SequenceNode): + if not sequence.args: + if node.else_clause: + return node.else_clause + else: + # don't break list comprehensions + return Nodes.StatListNode(node.pos, stats=[]) + # iterating over a list literal? => tuples are more efficient if isinstance(sequence, ExprNodes.ListNode): node.iterator.sequence = sequence.as_tuple() return node diff --git a/tests/run/constant_folding.py b/tests/run/constant_folding.py index 1040bd6..d88978a 100644 --- a/tests/run/constant_folding.py +++ b/tests/run/constant_folding.py @@ -185,3 +185,71 @@ def while_true(): return True else: print("FAIL") + + +@cython.test_fail_if_path_exists( + "//ForInStatNode", +) +def for_in_empty(): + """ + >>> for_in_empty() + """ + for i in []: + print("LOOP") + + +@cython.test_fail_if_path_exists( + "//ForInStatNode", +) +def for_in_empty_else(): + """ + >>> for_in_empty_else() + True + """ + for i in []: + print("LOOP") + else: + return True + + +@cython.test_fail_if_path_exists( + "//ForInStatNode", +) +@cython.test_assert_path_exists( + "//ComprehensionNode", +) +def for_in_empty_listcomp(): + """ + >>> for_in_empty_listcomp() + [] + """ + return [i for i in []] + + +@cython.test_fail_if_path_exists( + "//ForInStatNode", +) +@cython.test_assert_path_exists( + "//ComprehensionNode", +) +def for_in_empty_nested_listcomp(): + """ + >>> for_in_empty_nested_listcomp() + [] + """ + return [x for _ in [] for x in [1, 2, 3]] + + +@cython.test_fail_if_path_exists( + "//ForInStatNode//ForInStatNode", + ) +@cython.test_assert_path_exists( + "//ForInStatNode", + "//ComprehensionNode", +) +def for_in_nested_listcomp(): + """ + >>> for_in_nested_listcomp() + [] + """ + return [x for x in [1, 2, 3] for _ in []] diff --git a/tests/run/constant_folding_cy.pyx b/tests/run/constant_folding_cy.pyx index 3700a05..da9a935 100644 --- a/tests/run/constant_folding_cy.pyx +++ b/tests/run/constant_folding_cy.pyx @@ -80,3 +80,20 @@ def unicode_slicing_safe_surrogates2(): """ ustring = u'abc\U00010000def'[:2] return ustring + + +@cython.test_fail_if_path_exists( + "//ForInStatNode", +) +@cython.test_assert_path_exists( + "//ComprehensionNode", +) +def for_in_empty_setcomp(): + """ + >>> s = for_in_empty_setcomp() + >>> isinstance(s, set) + True + >>> len(s) + 0 + """ + return {i for i in []} -- 2.7.4