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

Unified Diff: Lib/test/test_compile.py

Issue 25843: lambdas on the same line may incorrectly share code objects
Patch Set: Created 4 years, 1 month ago
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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Include/code.h ('k') | Objects/codeobject.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
--- a/Lib/test/test_compile.py Thu Jan 21 08:58:44 2016 +0100
+++ b/Lib/test/test_compile.py Thu Jan 21 13:46:23 2016 +0100
@@ -572,6 +572,88 @@ if 1:
exec(memoryview(b"ax = 123")[1:-1], namespace)
self.assertEqual(namespace['x'], 12)
+ def check_constant(self, func, expected):
+ for const in func.__code__.co_consts:
+ if repr(const) == repr(expected):
+ break
+ else:
+ self.fail("unable to find constant %r in %r"
+ % (expected, func.__code__.co_consts))
+
+ # Merging equal constants is not a strict requirements for the Python
+ # semantics, it's a more an implementation detail.
+ @support.cpython_only
+ def test_merge_constants(self):
+ # Issue #25843: compile() must merge constants which are equal
+ # and have the same type.
+
+ def check_same_constant(const):
+ ns = {}
+ code = "f1, f2 = lambda: %r, lambda: %r" % (const, const)
+ exec(code, ns)
+ f1 = ns['f1']
+ f2 = ns['f2']
+ self.assertIs(f1.__code__, f2.__code__)
+ self.check_constant(f1, const)
+ self.assertEqual(repr(f1()), repr(const))
+
+ check_same_constant(None)
+ check_same_constant(0)
+ check_same_constant(0.0)
+ check_same_constant(b'abc')
+ check_same_constant('abc')
+
+ # Note: "lambda: ..." emits "LOAD_CONST Ellipsis",
+ # whereas "lambda: Ellipsis" emits "LOAD_GLOBAL Ellipsis"
+ f1, f2 = lambda: ..., lambda: ...
+ self.assertIs(f1.__code__, f2.__code__)
+ self.check_constant(f1, Ellipsis)
+ self.assertEqual(repr(f1()), repr(Ellipsis))
+
+ # {0} is converted to a constant frozenset({0}) by the peephole
+ # optimizer
+ f1, f2 = lambda x: x in {0}, lambda x: x in {0}
+ self.assertIs(f1.__code__, f2.__code__)
+ self.check_constant(f1, frozenset({0}))
+ self.assertTrue(f1(0))
+
+ def test_dont_merge_constants(self):
+ # Issue #25843: compile() must not merge constants which are equal
+ # but have a different type.
+
+ def check_different_constants(const1, const2):
+ ns = {}
+ exec("f1, f2 = lambda: %r, lambda: %r" % (const1, const2), ns)
+ f1 = ns['f1']
+ f2 = ns['f2']
+ self.assertIsNot(f1.__code__, f2.__code__)
+ self.check_constant(f1, const1)
+ self.check_constant(f2, const2)
+ self.assertEqual(repr(f1()), repr(const1))
+ self.assertEqual(repr(f2()), repr(const2))
+
+ check_different_constants(0, 0.0)
+ check_different_constants(+0.0, -0.0)
+ check_different_constants((0,), (0.0,))
+
+ # check_different_constants() cannot be used because repr(-0j) is
+ # '(-0-0j)', but when '(-0-0j)' is evaluated to 0j: we loose the sign.
+ f1, f2 = lambda: +0.0j, lambda: -0.0j
+ self.assertIsNot(f1.__code__, f2.__code__)
+ self.check_constant(f1, +0.0j)
+ self.check_constant(f2, -0.0j)
+ self.assertEqual(repr(f1()), repr(+0.0j))
+ self.assertEqual(repr(f2()), repr(-0.0j))
+
+ # {0} is converted to a constant frozenset({0}) by the peephole
+ # optimizer
+ f1, f2 = lambda x: x in {0}, lambda x: x in {0.0}
+ self.assertIsNot(f1.__code__, f2.__code__)
+ self.check_constant(f1, frozenset({0}))
+ self.check_constant(f2, frozenset({0.0}))
+ self.assertTrue(f1(0))
+ self.assertTrue(f2(0.0))
+
class TestStackSize(unittest.TestCase):
# These tests check that the computed stack size for a code object
« no previous file with comments | « Include/code.h ('k') | Objects/codeobject.c » ('j') | no next file with comments »

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