1import dis
2from itertools import combinations, product
3import textwrap
4import unittest
5
6from test.support.bytecode_helper import BytecodeTestCase
7
8
9def compile_pattern_with_fast_locals(pattern):
10    source = textwrap.dedent(
11        f"""
12        def f(x):
13            match x:
14                case {pattern}:
15                    pass
16        """
17    )
18    namespace = {}
19    exec(source, namespace)
20    return namespace["f"].__code__
21
22
23def count_instr_recursively(f, opname):
24    count = 0
25    for instr in dis.get_instructions(f):
26        if instr.opname == opname:
27            count += 1
28    if hasattr(f, '__code__'):
29        f = f.__code__
30    for c in f.co_consts:
31        if hasattr(c, 'co_code'):
32            count += count_instr_recursively(c, opname)
33    return count
34
35
36class TestTranforms(BytecodeTestCase):
37
38    def check_jump_targets(self, code):
39        instructions = list(dis.get_instructions(code))
40        targets = {instr.offset: instr for instr in instructions}
41        for instr in instructions:
42            if 'JUMP_' not in instr.opname:
43                continue
44            tgt = targets[instr.argval]
45            # jump to unconditional jump
46            if tgt.opname in ('JUMP_ABSOLUTE', 'JUMP_FORWARD'):
47                self.fail(f'{instr.opname} at {instr.offset} '
48                          f'jumps to {tgt.opname} at {tgt.offset}')
49            # unconditional jump to RETURN_VALUE
50            if (instr.opname in ('JUMP_ABSOLUTE', 'JUMP_FORWARD') and
51                tgt.opname == 'RETURN_VALUE'):
52                self.fail(f'{instr.opname} at {instr.offset} '
53                          f'jumps to {tgt.opname} at {tgt.offset}')
54            # JUMP_IF_*_OR_POP jump to conditional jump
55            if '_OR_POP' in instr.opname and 'JUMP_IF_' in tgt.opname:
56                self.fail(f'{instr.opname} at {instr.offset} '
57                          f'jumps to {tgt.opname} at {tgt.offset}')
58
59    def check_lnotab(self, code):
60        "Check that the lnotab byte offsets are sensible."
61        code = dis._get_code_object(code)
62        lnotab = list(dis.findlinestarts(code))
63        # Don't bother checking if the line info is sensible, because
64        # most of the line info we can get at comes from lnotab.
65        min_bytecode = min(t[0] for t in lnotab)
66        max_bytecode = max(t[0] for t in lnotab)
67        self.assertGreaterEqual(min_bytecode, 0)
68        self.assertLess(max_bytecode, len(code.co_code))
69        # This could conceivably test more (and probably should, as there
70        # aren't very many tests of lnotab), if peepholer wasn't scheduled
71        # to be replaced anyway.
72
73    def test_unot(self):
74        # UNARY_NOT POP_JUMP_IF_FALSE  -->  POP_JUMP_IF_TRUE'
75        def unot(x):
76            if not x == 2:
77                del x
78        self.assertNotInBytecode(unot, 'UNARY_NOT')
79        self.assertNotInBytecode(unot, 'POP_JUMP_FORWARD_IF_FALSE')
80        self.assertNotInBytecode(unot, 'POP_JUMP_BACKWARD_IF_FALSE')
81        self.assertInBytecode(unot, 'POP_JUMP_FORWARD_IF_TRUE')
82        self.check_lnotab(unot)
83
84    def test_elim_inversion_of_is_or_in(self):
85        for line, cmp_op, invert in (
86            ('not a is b', 'IS_OP', 1,),
87            ('not a is not b', 'IS_OP', 0,),
88            ('not a in b', 'CONTAINS_OP', 1,),
89            ('not a not in b', 'CONTAINS_OP', 0,),
90            ):
91            with self.subTest(line=line):
92                code = compile(line, '', 'single')
93                self.assertInBytecode(code, cmp_op, invert)
94                self.check_lnotab(code)
95
96    def test_global_as_constant(self):
97        # LOAD_GLOBAL None/True/False  -->  LOAD_CONST None/True/False
98        def f():
99            x = None
100            x = None
101            return x
102        def g():
103            x = True
104            return x
105        def h():
106            x = False
107            return x
108
109        for func, elem in ((f, None), (g, True), (h, False)):
110            with self.subTest(func=func):
111                self.assertNotInBytecode(func, 'LOAD_GLOBAL')
112                self.assertInBytecode(func, 'LOAD_CONST', elem)
113                self.check_lnotab(func)
114
115        def f():
116            'Adding a docstring made this test fail in Py2.5.0'
117            return None
118
119        self.assertNotInBytecode(f, 'LOAD_GLOBAL')
120        self.assertInBytecode(f, 'LOAD_CONST', None)
121        self.check_lnotab(f)
122
123    def test_while_one(self):
124        # Skip over:  LOAD_CONST trueconst  POP_JUMP_IF_FALSE xx
125        def f():
126            while 1:
127                pass
128            return list
129        for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
130            self.assertNotInBytecode(f, elem)
131        for elem in ('JUMP_BACKWARD',):
132            self.assertInBytecode(f, elem)
133        self.check_lnotab(f)
134
135    def test_pack_unpack(self):
136        for line, elem in (
137            ('a, = a,', 'LOAD_CONST',),
138            ('a, b = a, b', 'SWAP',),
139            ('a, b, c = a, b, c', 'SWAP',),
140            ):
141            with self.subTest(line=line):
142                code = compile(line,'','single')
143                self.assertInBytecode(code, elem)
144                self.assertNotInBytecode(code, 'BUILD_TUPLE')
145                self.assertNotInBytecode(code, 'UNPACK_SEQUENCE')
146                self.check_lnotab(code)
147
148    def test_folding_of_tuples_of_constants(self):
149        for line, elem in (
150            ('a = 1,2,3', (1, 2, 3)),
151            ('("a","b","c")', ('a', 'b', 'c')),
152            ('a,b,c = 1,2,3', (1, 2, 3)),
153            ('(None, 1, None)', (None, 1, None)),
154            ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
155            ):
156            with self.subTest(line=line):
157                code = compile(line,'','single')
158                self.assertInBytecode(code, 'LOAD_CONST', elem)
159                self.assertNotInBytecode(code, 'BUILD_TUPLE')
160                self.check_lnotab(code)
161
162        # Long tuples should be folded too.
163        code = compile(repr(tuple(range(10000))),'','single')
164        self.assertNotInBytecode(code, 'BUILD_TUPLE')
165        # One LOAD_CONST for the tuple, one for the None return value
166        load_consts = [instr for instr in dis.get_instructions(code)
167                              if instr.opname == 'LOAD_CONST']
168        self.assertEqual(len(load_consts), 2)
169        self.check_lnotab(code)
170
171        # Bug 1053819:  Tuple of constants misidentified when presented with:
172        # . . . opcode_with_arg 100   unary_opcode   BUILD_TUPLE 1  . . .
173        # The following would segfault upon compilation
174        def crater():
175            (~[
176                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
177                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
178                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
179                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
180                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
181                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
182                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
183                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
184                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
185                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
186            ],)
187        self.check_lnotab(crater)
188
189    def test_folding_of_lists_of_constants(self):
190        for line, elem in (
191            # in/not in constants with BUILD_LIST should be folded to a tuple:
192            ('a in [1,2,3]', (1, 2, 3)),
193            ('a not in ["a","b","c"]', ('a', 'b', 'c')),
194            ('a in [None, 1, None]', (None, 1, None)),
195            ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
196            ):
197            with self.subTest(line=line):
198                code = compile(line, '', 'single')
199                self.assertInBytecode(code, 'LOAD_CONST', elem)
200                self.assertNotInBytecode(code, 'BUILD_LIST')
201                self.check_lnotab(code)
202
203    def test_folding_of_sets_of_constants(self):
204        for line, elem in (
205            # in/not in constants with BUILD_SET should be folded to a frozenset:
206            ('a in {1,2,3}', frozenset({1, 2, 3})),
207            ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
208            ('a in {None, 1, None}', frozenset({1, None})),
209            ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
210            ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
211            ):
212            with self.subTest(line=line):
213                code = compile(line, '', 'single')
214                self.assertNotInBytecode(code, 'BUILD_SET')
215                self.assertInBytecode(code, 'LOAD_CONST', elem)
216                self.check_lnotab(code)
217
218        # Ensure that the resulting code actually works:
219        def f(a):
220            return a in {1, 2, 3}
221
222        def g(a):
223            return a not in {1, 2, 3}
224
225        self.assertTrue(f(3))
226        self.assertTrue(not f(4))
227        self.check_lnotab(f)
228
229        self.assertTrue(not g(3))
230        self.assertTrue(g(4))
231        self.check_lnotab(g)
232
233
234    def test_folding_of_binops_on_constants(self):
235        for line, elem in (
236            ('a = 2+3+4', 9),                   # chained fold
237            ('"@"*4', '@@@@'),                  # check string ops
238            ('a="abc" + "def"', 'abcdef'),      # check string ops
239            ('a = 3**4', 81),                   # binary power
240            ('a = 3*4', 12),                    # binary multiply
241            ('a = 13//4', 3),                   # binary floor divide
242            ('a = 14%4', 2),                    # binary modulo
243            ('a = 2+3', 5),                     # binary add
244            ('a = 13-4', 9),                    # binary subtract
245            ('a = (12,13)[1]', 13),             # binary subscr
246            ('a = 13 << 2', 52),                # binary lshift
247            ('a = 13 >> 2', 3),                 # binary rshift
248            ('a = 13 & 7', 5),                  # binary and
249            ('a = 13 ^ 7', 10),                 # binary xor
250            ('a = 13 | 7', 15),                 # binary or
251            ):
252            with self.subTest(line=line):
253                code = compile(line, '', 'single')
254                self.assertInBytecode(code, 'LOAD_CONST', elem)
255                for instr in dis.get_instructions(code):
256                    self.assertFalse(instr.opname.startswith('BINARY_'))
257                self.check_lnotab(code)
258
259        # Verify that unfoldables are skipped
260        code = compile('a=2+"b"', '', 'single')
261        self.assertInBytecode(code, 'LOAD_CONST', 2)
262        self.assertInBytecode(code, 'LOAD_CONST', 'b')
263        self.check_lnotab(code)
264
265        # Verify that large sequences do not result from folding
266        code = compile('a="x"*10000', '', 'single')
267        self.assertInBytecode(code, 'LOAD_CONST', 10000)
268        self.assertNotIn("x"*10000, code.co_consts)
269        self.check_lnotab(code)
270        code = compile('a=1<<1000', '', 'single')
271        self.assertInBytecode(code, 'LOAD_CONST', 1000)
272        self.assertNotIn(1<<1000, code.co_consts)
273        self.check_lnotab(code)
274        code = compile('a=2**1000', '', 'single')
275        self.assertInBytecode(code, 'LOAD_CONST', 1000)
276        self.assertNotIn(2**1000, code.co_consts)
277        self.check_lnotab(code)
278
279    def test_binary_subscr_on_unicode(self):
280        # valid code get optimized
281        code = compile('"foo"[0]', '', 'single')
282        self.assertInBytecode(code, 'LOAD_CONST', 'f')
283        self.assertNotInBytecode(code, 'BINARY_SUBSCR')
284        self.check_lnotab(code)
285        code = compile('"\u0061\uffff"[1]', '', 'single')
286        self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
287        self.assertNotInBytecode(code,'BINARY_SUBSCR')
288        self.check_lnotab(code)
289
290        # With PEP 393, non-BMP char get optimized
291        code = compile('"\U00012345"[0]', '', 'single')
292        self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
293        self.assertNotInBytecode(code, 'BINARY_SUBSCR')
294        self.check_lnotab(code)
295
296        # invalid code doesn't get optimized
297        # out of range
298        code = compile('"fuu"[10]', '', 'single')
299        self.assertInBytecode(code, 'BINARY_SUBSCR')
300        self.check_lnotab(code)
301
302    def test_folding_of_unaryops_on_constants(self):
303        for line, elem in (
304            ('-0.5', -0.5),                     # unary negative
305            ('-0.0', -0.0),                     # -0.0
306            ('-(1.0-1.0)', -0.0),               # -0.0 after folding
307            ('-0', 0),                          # -0
308            ('~-2', 1),                         # unary invert
309            ('+1', 1),                          # unary positive
310        ):
311            with self.subTest(line=line):
312                code = compile(line, '', 'single')
313                self.assertInBytecode(code, 'LOAD_CONST', elem)
314                for instr in dis.get_instructions(code):
315                    self.assertFalse(instr.opname.startswith('UNARY_'))
316                self.check_lnotab(code)
317
318        # Check that -0.0 works after marshaling
319        def negzero():
320            return -(1.0-1.0)
321
322        for instr in dis.get_instructions(negzero):
323            self.assertFalse(instr.opname.startswith('UNARY_'))
324        self.check_lnotab(negzero)
325
326        # Verify that unfoldables are skipped
327        for line, elem, opname in (
328            ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
329            ('~"abc"', 'abc', 'UNARY_INVERT'),
330        ):
331            with self.subTest(line=line):
332                code = compile(line, '', 'single')
333                self.assertInBytecode(code, 'LOAD_CONST', elem)
334                self.assertInBytecode(code, opname)
335                self.check_lnotab(code)
336
337    def test_elim_extra_return(self):
338        # RETURN LOAD_CONST None RETURN  -->  RETURN
339        def f(x):
340            return x
341        self.assertNotInBytecode(f, 'LOAD_CONST', None)
342        returns = [instr for instr in dis.get_instructions(f)
343                          if instr.opname == 'RETURN_VALUE']
344        self.assertEqual(len(returns), 1)
345        self.check_lnotab(f)
346
347    @unittest.skip("Following gh-92228 the return has two predecessors "
348                   "and that prevents jump elimination.")
349    def test_elim_jump_to_return(self):
350        # JUMP_FORWARD to RETURN -->  RETURN
351        def f(cond, true_value, false_value):
352            # Intentionally use two-line expression to test issue37213.
353            return (true_value if cond
354                    else false_value)
355        self.check_jump_targets(f)
356        self.assertNotInBytecode(f, 'JUMP_FORWARD')
357        self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
358        returns = [instr for instr in dis.get_instructions(f)
359                          if instr.opname == 'RETURN_VALUE']
360        self.assertEqual(len(returns), 2)
361        self.check_lnotab(f)
362
363    def test_elim_jump_to_uncond_jump(self):
364        # POP_JUMP_IF_FALSE to JUMP_FORWARD --> POP_JUMP_IF_FALSE to non-jump
365        def f():
366            if a:
367                # Intentionally use two-line expression to test issue37213.
368                if (c
369                    or d):
370                    foo()
371            else:
372                baz()
373        self.check_jump_targets(f)
374        self.check_lnotab(f)
375
376    def test_elim_jump_to_uncond_jump2(self):
377        # POP_JUMP_IF_FALSE to JUMP_ABSOLUTE --> POP_JUMP_IF_FALSE to non-jump
378        def f():
379            while a:
380                # Intentionally use two-line expression to test issue37213.
381                if (c
382                    or d):
383                    a = foo()
384        self.check_jump_targets(f)
385        self.check_lnotab(f)
386
387    def test_elim_jump_to_uncond_jump3(self):
388        # Intentionally use two-line expressions to test issue37213.
389        # JUMP_IF_FALSE_OR_POP to JUMP_IF_FALSE_OR_POP --> JUMP_IF_FALSE_OR_POP to non-jump
390        def f(a, b, c):
391            return ((a and b)
392                    and c)
393        self.check_jump_targets(f)
394        self.check_lnotab(f)
395        self.assertEqual(count_instr_recursively(f, 'JUMP_IF_FALSE_OR_POP'), 2)
396        # JUMP_IF_TRUE_OR_POP to JUMP_IF_TRUE_OR_POP --> JUMP_IF_TRUE_OR_POP to non-jump
397        def f(a, b, c):
398            return ((a or b)
399                    or c)
400        self.check_jump_targets(f)
401        self.check_lnotab(f)
402        self.assertEqual(count_instr_recursively(f, 'JUMP_IF_TRUE_OR_POP'), 2)
403        # JUMP_IF_FALSE_OR_POP to JUMP_IF_TRUE_OR_POP --> POP_JUMP_IF_FALSE to non-jump
404        def f(a, b, c):
405            return ((a and b)
406                    or c)
407        self.check_jump_targets(f)
408        self.check_lnotab(f)
409        self.assertNotInBytecode(f, 'JUMP_IF_FALSE_OR_POP')
410        self.assertInBytecode(f, 'JUMP_IF_TRUE_OR_POP')
411        self.assertInBytecode(f, 'POP_JUMP_FORWARD_IF_FALSE')
412        # JUMP_IF_TRUE_OR_POP to JUMP_IF_FALSE_OR_POP --> POP_JUMP_IF_TRUE to non-jump
413        def f(a, b, c):
414            return ((a or b)
415                    and c)
416        self.check_jump_targets(f)
417        self.check_lnotab(f)
418        self.assertNotInBytecode(f, 'JUMP_IF_TRUE_OR_POP')
419        self.assertInBytecode(f, 'JUMP_IF_FALSE_OR_POP')
420        self.assertInBytecode(f, 'POP_JUMP_FORWARD_IF_TRUE')
421
422    def test_elim_jump_after_return1(self):
423        # Eliminate dead code: jumps immediately after returns can't be reached
424        def f(cond1, cond2):
425            if cond1: return 1
426            if cond2: return 2
427            while 1:
428                return 3
429            while 1:
430                if cond1: return 4
431                return 5
432            return 6
433        self.assertNotInBytecode(f, 'JUMP_FORWARD')
434        self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
435        returns = [instr for instr in dis.get_instructions(f)
436                          if instr.opname == 'RETURN_VALUE']
437        self.assertLessEqual(len(returns), 6)
438        self.check_lnotab(f)
439
440    def test_make_function_doesnt_bail(self):
441        def f():
442            def g()->1+1:
443                pass
444            return g
445        self.assertNotInBytecode(f, 'BINARY_OP')
446        self.check_lnotab(f)
447
448    def test_constant_folding(self):
449        # Issue #11244: aggressive constant folding.
450        exprs = [
451            '3 * -5',
452            '-3 * 5',
453            '2 * (3 * 4)',
454            '(2 * 3) * 4',
455            '(-1, 2, 3)',
456            '(1, -2, 3)',
457            '(1, 2, -3)',
458            '(1, 2, -3) * 6',
459            'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
460        ]
461        for e in exprs:
462            with self.subTest(e=e):
463                code = compile(e, '', 'single')
464                for instr in dis.get_instructions(code):
465                    self.assertFalse(instr.opname.startswith('UNARY_'))
466                    self.assertFalse(instr.opname.startswith('BINARY_'))
467                    self.assertFalse(instr.opname.startswith('BUILD_'))
468                self.check_lnotab(code)
469
470    def test_in_literal_list(self):
471        def containtest():
472            return x in [a, b]
473        self.assertEqual(count_instr_recursively(containtest, 'BUILD_LIST'), 0)
474        self.check_lnotab(containtest)
475
476    def test_iterate_literal_list(self):
477        def forloop():
478            for x in [a, b]:
479                pass
480        self.assertEqual(count_instr_recursively(forloop, 'BUILD_LIST'), 0)
481        self.check_lnotab(forloop)
482
483    def test_condition_with_binop_with_bools(self):
484        def f():
485            if True or False:
486                return 1
487            return 0
488        self.assertEqual(f(), 1)
489        self.check_lnotab(f)
490
491    def test_if_with_if_expression(self):
492        # Check bpo-37289
493        def f(x):
494            if (True if x else False):
495                return True
496            return False
497        self.assertTrue(f(True))
498        self.check_lnotab(f)
499
500    def test_trailing_nops(self):
501        # Check the lnotab of a function that even after trivial
502        # optimization has trailing nops, which the lnotab adjustment has to
503        # handle properly (bpo-38115).
504        def f(x):
505            while 1:
506                return 3
507            while 1:
508                return 5
509            return 6
510        self.check_lnotab(f)
511
512    def test_assignment_idiom_in_comprehensions(self):
513        def listcomp():
514            return [y for x in a for y in [f(x)]]
515        self.assertEqual(count_instr_recursively(listcomp, 'FOR_ITER'), 1)
516        def setcomp():
517            return {y for x in a for y in [f(x)]}
518        self.assertEqual(count_instr_recursively(setcomp, 'FOR_ITER'), 1)
519        def dictcomp():
520            return {y: y for x in a for y in [f(x)]}
521        self.assertEqual(count_instr_recursively(dictcomp, 'FOR_ITER'), 1)
522        def genexpr():
523            return (y for x in a for y in [f(x)])
524        self.assertEqual(count_instr_recursively(genexpr, 'FOR_ITER'), 1)
525
526    def test_format_combinations(self):
527        flags = '-+ #0'
528        testcases = [
529            *product(('', '1234', 'абвг'), 'sra'),
530            *product((1234, -1234), 'duioxX'),
531            *product((1234.5678901, -1234.5678901), 'duifegFEG'),
532            *product((float('inf'), -float('inf')), 'fegFEG'),
533        ]
534        width_precs = [
535            *product(('', '1', '30'), ('', '.', '.0', '.2')),
536            ('', '.40'),
537            ('30', '.40'),
538        ]
539        for value, suffix in testcases:
540            for width, prec in width_precs:
541                for r in range(len(flags) + 1):
542                    for spec in combinations(flags, r):
543                        fmt = '%' + ''.join(spec) + width + prec + suffix
544                        with self.subTest(fmt=fmt, value=value):
545                            s1 = fmt % value
546                            s2 = eval(f'{fmt!r} % (x,)', {'x': value})
547                            self.assertEqual(s2, s1, f'{fmt = }')
548
549    def test_format_misc(self):
550        def format(fmt, *values):
551            vars = [f'x{i+1}' for i in range(len(values))]
552            if len(vars) == 1:
553                args = '(' + vars[0] + ',)'
554            else:
555                args = '(' + ', '.join(vars) + ')'
556            return eval(f'{fmt!r} % {args}', dict(zip(vars, values)))
557
558        self.assertEqual(format('string'), 'string')
559        self.assertEqual(format('x = %s!', 1234), 'x = 1234!')
560        self.assertEqual(format('x = %d!', 1234), 'x = 1234!')
561        self.assertEqual(format('x = %x!', 1234), 'x = 4d2!')
562        self.assertEqual(format('x = %f!', 1234), 'x = 1234.000000!')
563        self.assertEqual(format('x = %s!', 1234.5678901), 'x = 1234.5678901!')
564        self.assertEqual(format('x = %f!', 1234.5678901), 'x = 1234.567890!')
565        self.assertEqual(format('x = %d!', 1234.5678901), 'x = 1234!')
566        self.assertEqual(format('x = %s%% %%%%', 1234), 'x = 1234% %%')
567        self.assertEqual(format('x = %s!', '%% %s'), 'x = %% %s!')
568        self.assertEqual(format('x = %s, y = %d', 12, 34), 'x = 12, y = 34')
569
570    def test_format_errors(self):
571        with self.assertRaisesRegex(TypeError,
572                    'not enough arguments for format string'):
573            eval("'%s' % ()")
574        with self.assertRaisesRegex(TypeError,
575                    'not all arguments converted during string formatting'):
576            eval("'%s' % (x, y)", {'x': 1, 'y': 2})
577        with self.assertRaisesRegex(ValueError, 'incomplete format'):
578            eval("'%s%' % (x,)", {'x': 1234})
579        with self.assertRaisesRegex(ValueError, 'incomplete format'):
580            eval("'%s%%%' % (x,)", {'x': 1234})
581        with self.assertRaisesRegex(TypeError,
582                    'not enough arguments for format string'):
583            eval("'%s%z' % (x,)", {'x': 1234})
584        with self.assertRaisesRegex(ValueError, 'unsupported format character'):
585            eval("'%s%z' % (x, 5)", {'x': 1234})
586        with self.assertRaisesRegex(TypeError, 'a real number is required, not str'):
587            eval("'%d' % (x,)", {'x': '1234'})
588        with self.assertRaisesRegex(TypeError, 'an integer is required, not float'):
589            eval("'%x' % (x,)", {'x': 1234.56})
590        with self.assertRaisesRegex(TypeError, 'an integer is required, not str'):
591            eval("'%x' % (x,)", {'x': '1234'})
592        with self.assertRaisesRegex(TypeError, 'must be real number, not str'):
593            eval("'%f' % (x,)", {'x': '1234'})
594        with self.assertRaisesRegex(TypeError,
595                    'not enough arguments for format string'):
596            eval("'%s, %s' % (x, *y)", {'x': 1, 'y': []})
597        with self.assertRaisesRegex(TypeError,
598                    'not all arguments converted during string formatting'):
599            eval("'%s, %s' % (x, *y)", {'x': 1, 'y': [2, 3]})
600
601    def test_static_swaps_unpack_two(self):
602        def f(a, b):
603            a, b = a, b
604            b, a = a, b
605        self.assertNotInBytecode(f, "SWAP")
606
607    def test_static_swaps_unpack_three(self):
608        def f(a, b, c):
609            a, b, c = a, b, c
610            a, c, b = a, b, c
611            b, a, c = a, b, c
612            b, c, a = a, b, c
613            c, a, b = a, b, c
614            c, b, a = a, b, c
615        self.assertNotInBytecode(f, "SWAP")
616
617    def test_static_swaps_match_mapping(self):
618        for a, b, c in product("_a", "_b", "_c"):
619            pattern = f"{{'a': {a}, 'b': {b}, 'c': {c}}}"
620            with self.subTest(pattern):
621                code = compile_pattern_with_fast_locals(pattern)
622                self.assertNotInBytecode(code, "SWAP")
623
624    def test_static_swaps_match_class(self):
625        forms = [
626            "C({}, {}, {})",
627            "C({}, {}, c={})",
628            "C({}, b={}, c={})",
629            "C(a={}, b={}, c={})"
630        ]
631        for a, b, c in product("_a", "_b", "_c"):
632            for form in forms:
633                pattern = form.format(a, b, c)
634                with self.subTest(pattern):
635                    code = compile_pattern_with_fast_locals(pattern)
636                    self.assertNotInBytecode(code, "SWAP")
637
638    def test_static_swaps_match_sequence(self):
639        swaps = {"*_, b, c", "a, *_, c", "a, b, *_"}
640        forms = ["{}, {}, {}", "{}, {}, *{}", "{}, *{}, {}", "*{}, {}, {}"]
641        for a, b, c in product("_a", "_b", "_c"):
642            for form in forms:
643                pattern = form.format(a, b, c)
644                with self.subTest(pattern):
645                    code = compile_pattern_with_fast_locals(pattern)
646                    if pattern in swaps:
647                        # If this fails... great! Remove this pattern from swaps
648                        # to prevent regressing on any improvement:
649                        self.assertInBytecode(code, "SWAP")
650                    else:
651                        self.assertNotInBytecode(code, "SWAP")
652
653
654class TestBuglets(unittest.TestCase):
655
656    def test_bug_11510(self):
657        # folded constant set optimization was commingled with the tuple
658        # unpacking optimization which would fail if the set had duplicate
659        # elements so that the set length was unexpected
660        def f():
661            x, y = {1, 1}
662            return x, y
663        with self.assertRaises(ValueError):
664            f()
665
666    def test_bpo_42057(self):
667        for i in range(10):
668            try:
669                raise Exception
670            except Exception or Exception:
671                pass
672
673    def test_bpo_45773_pop_jump_if_true(self):
674        compile("while True or spam: pass", "<test>", "exec")
675
676    def test_bpo_45773_pop_jump_if_false(self):
677        compile("while True or not spam: pass", "<test>", "exec")
678
679
680if __name__ == "__main__":
681    unittest.main()
682