summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_peepholer.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_peepholer.py')
-rw-r--r--Lib/test/test_peepholer.py143
1 files changed, 109 insertions, 34 deletions
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index 7e05f49..e268ae2 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -1,6 +1,7 @@
import dis
+import re
import sys
-from cStringIO import StringIO
+from io import StringIO
import unittest
def disassemble(func):
@@ -19,14 +20,15 @@ def dis_single(line):
class TestTranforms(unittest.TestCase):
def test_unot(self):
- # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE
+ # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
def unot(x):
if not x == 2:
del x
asm = disassemble(unot)
for elem in ('UNARY_NOT', 'POP_JUMP_IF_FALSE'):
self.assertNotIn(elem, asm)
- self.assertIn('POP_JUMP_IF_TRUE', asm)
+ for elem in ('POP_JUMP_IF_TRUE',):
+ self.assertIn(elem, asm)
def test_elim_inversion_of_is_or_in(self):
for line, elem in (
@@ -38,16 +40,24 @@ class TestTranforms(unittest.TestCase):
asm = dis_single(line)
self.assertIn(elem, asm)
- def test_none_as_constant(self):
- # LOAD_GLOBAL None --> LOAD_CONST None
+ def test_global_as_constant(self):
+ # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
def f(x):
None
+ None
return x
- asm = disassemble(f)
- for elem in ('LOAD_GLOBAL',):
- self.assertNotIn(elem, asm)
- for elem in ('LOAD_CONST', '(None)'):
- self.assertIn(elem, asm)
+ def g(x):
+ True
+ return x
+ def h(x):
+ False
+ return x
+ for func, name in ((f, 'None'), (g, 'True'), (h, 'False')):
+ asm = disassemble(func)
+ for elem in ('LOAD_GLOBAL',):
+ self.assertNotIn(elem, asm)
+ for elem in ('LOAD_CONST', '('+name+')'):
+ self.assertIn(elem, asm)
def f():
'Adding a docstring made this test fail in Py2.5.0'
return None
@@ -106,6 +116,54 @@ class TestTranforms(unittest.TestCase):
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
],)
+ def test_folding_of_lists_of_constants(self):
+ for line, elem in (
+ # in/not in constants with BUILD_LIST should be folded to a tuple:
+ ('a in [1,2,3]', '(1, 2, 3)'),
+ ('a not in ["a","b","c"]', "(('a', 'b', 'c'))"),
+ ('a in [None, 1, None]', '((None, 1, None))'),
+ ('a not in [(1, 2), 3, 4]', '(((1, 2), 3, 4))'),
+ ):
+ asm = dis_single(line)
+ self.assertIn(elem, asm)
+ self.assertNotIn('BUILD_LIST', asm)
+
+ def test_folding_of_sets_of_constants(self):
+ for line, elem in (
+ # in/not in constants with BUILD_SET should be folded to a frozenset:
+ ('a in {1,2,3}', frozenset({1, 2, 3})),
+ ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
+ ('a in {None, 1, None}', frozenset({1, None})),
+ ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
+ ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
+ ):
+ asm = dis_single(line)
+ self.assertNotIn('BUILD_SET', asm)
+
+ # Verify that the frozenset 'elem' is in the disassembly
+ # The ordering of the elements in repr( frozenset ) isn't
+ # guaranteed, so we jump through some hoops to ensure that we have
+ # the frozenset we expect:
+ self.assertIn('frozenset', asm)
+ # Extract the frozenset literal from the disassembly:
+ m = re.match(r'.*(frozenset\({.*}\)).*', asm, re.DOTALL)
+ self.assertTrue(m)
+ self.assertEqual(eval(m.group(1)), elem)
+
+ # Ensure that the resulting code actually works:
+ def f(a):
+ return a in {1, 2, 3}
+
+ def g(a):
+ return a not in {1, 2, 3}
+
+ self.assertTrue(f(3))
+ self.assertTrue(not f(4))
+
+ self.assertTrue(not g(3))
+ self.assertTrue(g(4))
+
+
def test_folding_of_binops_on_constants(self):
for line, elem in (
('a = 2+3+4', '(9)'), # chained fold
@@ -139,28 +197,28 @@ class TestTranforms(unittest.TestCase):
def test_binary_subscr_on_unicode(self):
# unicode strings don't get optimized
- asm = dis_single('u"foo"[0]')
- self.assertNotIn("(u'f')", asm)
+ asm = dis_single('"foo"[0]')
+ self.assertNotIn("('f')", asm)
self.assertIn('BINARY_SUBSCR', asm)
- asm = dis_single('u"\u0061\uffff"[1]')
- self.assertNotIn("(u'\\uffff')", asm)
+ asm = dis_single('"\u0061\uffff"[1]')
+ self.assertNotIn("('\\uffff')", asm)
self.assertIn('BINARY_SUBSCR', asm)
# out of range
- asm = dis_single('u"fuu"[10]')
+ asm = dis_single('"fuu"[10]')
self.assertIn('BINARY_SUBSCR', asm)
# non-BMP char (see #5057)
- asm = dis_single('u"\U00012345"[0]')
+ asm = dis_single('"\U00012345"[0]')
self.assertIn('BINARY_SUBSCR', asm)
- asm = dis_single('u"\U00012345abcdef"[3]')
+ asm = dis_single('"\U00012345abcdef"[3]')
self.assertIn('BINARY_SUBSCR', asm)
def test_folding_of_unaryops_on_constants(self):
for line, elem in (
- ('`1`', "('1')"), # unary convert
('-0.5', '(-0.5)'), # unary negative
('~-2', '(1)'), # unary invert
+ ('+1', '(1)'), # unary positive
):
asm = dis_single(line)
self.assertIn(elem, asm, asm)
@@ -220,25 +278,42 @@ class TestTranforms(unittest.TestCase):
self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1)
self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
+ def test_make_function_doesnt_bail(self):
+ def f():
+ def g()->1+1:
+ pass
+ return g
+ asm = disassemble(f)
+ self.assertNotIn('BINARY_ADD', asm)
+
+class TestBuglets(unittest.TestCase):
+
+ def test_bug_11510(self):
+ # folded constant set optimization was commingled with the tuple
+ # unpacking optimization which would fail if the set had duplicate
+ # elements so that the set length was unexpected
+ def f():
+ x, y = {1, 1}
+ return x, y
+ with self.assertRaises(ValueError):
+ f()
+
def test_main(verbose=None):
import sys
- from test import test_support
- test_classes = (TestTranforms,)
-
- with test_support.check_py3k_warnings(
- ("backquote not supported", SyntaxWarning)):
- test_support.run_unittest(*test_classes)
-
- # verify reference counting
- if verbose and hasattr(sys, "gettotalrefcount"):
- import gc
- counts = [None] * 5
- for i in xrange(len(counts)):
- test_support.run_unittest(*test_classes)
- gc.collect()
- counts[i] = sys.gettotalrefcount()
- print counts
+ from test import support
+ test_classes = (TestTranforms, TestBuglets)
+ support.run_unittest(*test_classes)
+
+ # verify reference counting
+ if verbose and hasattr(sys, "gettotalrefcount"):
+ import gc
+ counts = [None] * 5
+ for i in range(len(counts)):
+ support.run_unittest(*test_classes)
+ gc.collect()
+ counts[i] = sys.gettotalrefcount()
+ print(counts)
if __name__ == "__main__":
test_main(verbose=True)