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

Delta Between Two Patch Sets: Lib/test/test_compile.py

Issue 25843: lambdas on the same line may incorrectly share code objects
Left Patch Set: Created 4 years, 1 month ago
Right Patch Set: Created 4 years, 1 month 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Include/code.h ('k') | Objects/codeobject.c » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 556 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 574
575 def check_constant(self, func, expected): 575 def check_constant(self, func, expected):
576 for const in func.__code__.co_consts: 576 for const in func.__code__.co_consts:
577 if const != expected or type(const) != type(expected): 577 if repr(const) == repr(expected):
578 continue 578 break
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: 579 else:
585 self.fail("unable to find constant %r in %r" 580 self.fail("unable to find constant %r in %r"
586 % (expected, func.__code__.co_consts)) 581 % (expected, func.__code__.co_consts))
587 582
588 # Merging equal constants is not a strict requirements for the Python 583 # Merging equal constants is not a strict requirements for the Python
589 # semantics, it's a more an implementation detail. 584 # semantics, it's a more an implementation detail.
590 @support.cpython_only 585 @support.cpython_only
591 def test_merge_constants(self): 586 def test_merge_constants(self):
592 # Issue #25843: compile() must merge constants which are equal 587 # Issue #25843: compile() must merge constants which are equal
593 # and have the same type. 588 # and have the same type.
594 589
595 def check_same_constant(const): 590 def check_same_constant(const):
596 ns = {} 591 ns = {}
597 code = "f1, f2 = lambda: %r, lambda: %r" % (const, const) 592 code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
598 exec(code, ns) 593 exec(code, ns)
599 f1 = ns['f1'] 594 f1 = ns['f1']
600 f2 = ns['f2'] 595 f2 = ns['f2']
601 self.assertIs(f1.__code__, f2.__code__) 596 self.assertIs(f1.__code__, f2.__code__)
602 self.check_constant(f1, const) 597 self.check_constant(f1, const)
598 self.assertEqual(repr(f1()), repr(const))
603 599
604 check_same_constant(None) 600 check_same_constant(None)
605 check_same_constant(0) 601 check_same_constant(0)
606 check_same_constant(0.0) 602 check_same_constant(0.0)
607 check_same_constant(b'abc') 603 check_same_constant(b'abc')
608 check_same_constant('abc') 604 check_same_constant('abc')
609 605
610 # Note: "lambda: ..." emits "LOAD_CONST Ellipsis", 606 # Note: "lambda: ..." emits "LOAD_CONST Ellipsis",
611 # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis" 607 # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis"
612 f1, f2 = lambda: ..., lambda: ... 608 f1, f2 = lambda: ..., lambda: ...
613 self.assertIs(f1.__code__, f2.__code__) 609 self.assertIs(f1.__code__, f2.__code__)
614 self.check_constant(f1, Ellipsis) 610 self.check_constant(f1, Ellipsis)
611 self.assertEqual(repr(f1()), repr(Ellipsis))
615 612
616 # {0} is converted to a constant frozenset({0}) by the peephole 613 # {0} is converted to a constant frozenset({0}) by the peephole
617 # optimizer 614 # optimizer
618 f1, f2 = lambda x: x in {0}, lambda x: x in {0} 615 f1, f2 = lambda x: x in {0}, lambda x: x in {0}
619 self.assertIs(f1.__code__, f2.__code__) 616 self.assertIs(f1.__code__, f2.__code__)
620 self.check_constant(f1, frozenset({0})) 617 self.check_constant(f1, frozenset({0}))
618 self.assertTrue(f1(0))
621 619
622 def test_dont_merge_constants(self): 620 def test_dont_merge_constants(self):
623 # Issue #25843: compile() must not merge constants which are equal 621 # Issue #25843: compile() must not merge constants which are equal
624 # but have a different type. 622 # but have a different type.
625 623
626 def check_different_constants(const1, const2): 624 def check_different_constants(const1, const2):
627 ns = {} 625 ns = {}
628 exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns) 626 exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
629 f1 = ns['f1'] 627 f1 = ns['f1']
630 f2 = ns['f2'] 628 f2 = ns['f2']
631 self.assertIsNot(f1.__code__, f2.__code__) 629 self.assertIsNot(f1.__code__, f2.__code__)
632 self.check_constant(f1, const1) 630 self.check_constant(f1, const1)
633 self.check_constant(f2, const2) 631 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.
632 self.assertEqual(repr(f1()), repr(const1))
633 self.assertEqual(repr(f2()), repr(const2))
634 634
635 check_different_constants(0, 0.0) 635 check_different_constants(0, 0.0)
636 check_different_constants(+0.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,)) 637 check_different_constants((0,), (0.0,))
638
639 # check_different_constants() cannot be used because repr(-0j) is
640 # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign.
641 f1, f2 = lambda: +0.0j, lambda: -0.0j
642 self.assertIsNot(f1.__code__, f2.__code__)
643 self.check_constant(f1, +0.0j)
644 self.check_constant(f2, -0.0j)
645 self.assertEqual(repr(f1()), repr(+0.0j))
646 self.assertEqual(repr(f2()), repr(-0.0j))
639 647
640 # {0} is converted to a constant frozenset({0}) by the peephole 648 # {0} is converted to a constant frozenset({0}) by the peephole
641 # optimizer 649 # optimizer
642 f1, f2 = lambda x: x in {0}, lambda x: x in {0.0} 650 f1, f2 = lambda x: x in {0}, lambda x: x in {0.0}
643 self.assertIsNot(f1.__code__, f2.__code__) 651 self.assertIsNot(f1.__code__, f2.__code__)
644 self.check_constant(f1, frozenset({0})) 652 self.check_constant(f1, frozenset({0}))
645 self.check_constant(f2, frozenset({0.0})) 653 self.check_constant(f2, frozenset({0.0}))
654 self.assertTrue(f1(0))
655 self.assertTrue(f2(0.0))
646 656
647 657
648 class TestStackSize(unittest.TestCase): 658 class TestStackSize(unittest.TestCase):
649 # These tests check that the computed stack size for a code object 659 # These tests check that the computed stack size for a code object
650 # stays within reasonable bounds (see issue #21523 for an example 660 # stays within reasonable bounds (see issue #21523 for an example
651 # dysfunction). 661 # dysfunction).
652 N = 100 662 N = 100
653 663
654 def check_stack_size(self, code): 664 def check_stack_size(self, code):
655 # To assert that the alleged stack size is not O(N), we 665 # To assert that the alleged stack size is not O(N), we
(...skipping 22 matching lines...) Expand all
678 self.check_stack_size("x + " * self.N + "x") 688 self.check_stack_size("x + " * self.N + "x")
679 689
680 def test_func_and(self): 690 def test_func_and(self):
681 code = "def f(x):\n" 691 code = "def f(x):\n"
682 code += " x and x\n" * self.N 692 code += " x and x\n" * self.N
683 self.check_stack_size(code) 693 self.check_stack_size(code)
684 694
685 695
686 if __name__ == "__main__": 696 if __name__ == "__main__":
687 unittest.main() 697 unittest.main()
LEFTRIGHT

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