Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(27)

Side by Side Diff: Lib/test/test_compile.py

Issue 25843: lambdas on the same line may incorrectly share code objects
Patch Set: Created 4 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 import math 1 import math
2 import os 2 import os
3 import unittest 3 import unittest
4 import sys 4 import sys
5 import _ast 5 import _ast
6 import tempfile 6 import tempfile
7 import types 7 import types
8 from test import support 8 from test import support
9 from test.support import script_helper 9 from test.support import script_helper
10 10
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval") 564 code = compile(memoryview(b"1234")[1:-1], "<dummy>", "eval")
565 self.assertEqual(eval(code), 23) 565 self.assertEqual(eval(code), 23)
566 code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval") 566 code = compile(memoryview(b"$23$")[1:-1], "<dummy>", "eval")
567 self.assertEqual(eval(code), 23) 567 self.assertEqual(eval(code), 23)
568 568
569 # Also test when eval() and exec() do the compilation step 569 # Also test when eval() and exec() do the compilation step
570 self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23) 570 self.assertEqual(eval(memoryview(b"1234")[1:-1]), 23)
571 namespace = dict() 571 namespace = dict()
572 exec(memoryview(b"ax = 123")[1:-1], namespace) 572 exec(memoryview(b"ax = 123")[1:-1], namespace)
573 self.assertEqual(namespace['x'], 12) 573 self.assertEqual(namespace['x'], 12)
574
575 def check_constant(self, func, expected):
576 for const in func.__code__.co_consts:
577 if const != expected or type(const) != type(expected):
578 continue
579 if type(expected) in (tuple, frozenset):
580 if list(map(type, const)) != list(map(type, expected)):
581 continue
582 # its ok, we found it
583 break
584 else:
585 self.fail("unable to find constant %r in %r"
586 % (expected, func.__code__.co_consts))
587
588 # Merging equal constants is not a strict requirements for the Python
589 # semantics, it's a more an implementation detail.
590 @support.cpython_only
591 def test_merge_constants(self):
592 # Issue #25843: compile() must merge constants which are equal
593 # and have the same type.
594
595 def check_same_constant(const):
596 ns = {}
597 code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
598 exec(code, ns)
599 f1 = ns['f1']
600 f2 = ns['f2']
601 self.assertIs(f1.__code__, f2.__code__)
602 self.check_constant(f1, const)
603
604 check_same_constant(None)
605 check_same_constant(0)
606 check_same_constant(0.0)
607 check_same_constant(b'abc')
608 check_same_constant('abc')
609
610 # Note: "lambda: ..." emits "LOAD_CONST Ellipsis",
611 # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis"
612 f1, f2 = lambda: ..., lambda: ...
613 self.assertIs(f1.__code__, f2.__code__)
614 self.check_constant(f1, Ellipsis)
615
616 # {0} is converted to a constant frozenset({0}) by the peephole
617 # optimizer
618 f1, f2 = lambda x: x in {0}, lambda x: x in {0}
619 self.assertIs(f1.__code__, f2.__code__)
620 self.check_constant(f1, frozenset({0}))
621
622 def test_dont_merge_constants(self):
623 # Issue #25843: compile() must not merge constants which are equal
624 # but have a different type.
625
626 def check_different_constants(const1, const2):
627 ns = {}
628 exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
629 f1 = ns['f1']
630 f2 = ns['f2']
631 self.assertIsNot(f1.__code__, f2.__code__)
632 self.check_constant(f1, const1)
633 self.check_constant(f2, const2)
storchaka 2016/01/20 19:19:01 Assert repr(f1()) == repr(const1) and repr(f2())
haypo 2016/01/22 12:24:14 Good idea, thanks for the hint.
634
635 check_different_constants(0, 0.0)
636 check_different_constants(+0.0, -0.0)
storchaka 2016/01/20 19:19:01 In Python 3 this test is passed because co_consts
haypo 2016/01/22 12:24:14 IMHO it's overkill to check the exact list of cons
637 check_different_constants(+0.0j, -0.0j)
638 check_different_constants((0,), (0.0,))
639
640 # {0} is converted to a constant frozenset({0}) by the peephole
641 # optimizer
642 f1, f2 = lambda x: x in {0}, lambda x: x in {0.0}
643 self.assertIsNot(f1.__code__, f2.__code__)
644 self.check_constant(f1, frozenset({0}))
645 self.check_constant(f2, frozenset({0.0}))
574 646
575 647
576 class TestStackSize(unittest.TestCase): 648 class TestStackSize(unittest.TestCase):
577 # These tests check that the computed stack size for a code object 649 # These tests check that the computed stack size for a code object
578 # stays within reasonable bounds (see issue #21523 for an example 650 # stays within reasonable bounds (see issue #21523 for an example
579 # dysfunction). 651 # dysfunction).
580 N = 100 652 N = 100
581 653
582 def check_stack_size(self, code): 654 def check_stack_size(self, code):
583 # To assert that the alleged stack size is not O(N), we 655 # To assert that the alleged stack size is not O(N), we
(...skipping 22 matching lines...) Expand all
606 self.check_stack_size("x + " * self.N + "x") 678 self.check_stack_size("x + " * self.N + "x")
607 679
608 def test_func_and(self): 680 def test_func_and(self):
609 code = "def f(x):\n" 681 code = "def f(x):\n"
610 code += " x and x\n" * self.N 682 code += " x and x\n" * self.N
611 self.check_stack_size(code) 683 self.check_stack_size(code)
612 684
613 685
614 if __name__ == "__main__": 686 if __name__ == "__main__":
615 unittest.main() 687 unittest.main()
OLDNEW

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+