[pypy-svn] pypy cmath: (lac, arigo)

arigo commits-noreply at bitbucket.org
Tue Jan 18 15:45:26 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: cmath
Changeset: r40863:263f1644fa25
Date: 2011-01-18 15:43 +0100
http://bitbucket.org/pypy/pypy/changeset/263f1644fa25/

Log:	(lac, arigo)

	Fix the detection of 0.0 vs -0.0, and more generally of nested
	tuples.

diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -834,21 +834,7 @@
     def visit_Const(self, const):
         self.update_position(const.lineno)
         space = self.space
-        value = const.value
-        # Constant tuples are tricky because we have to avoid letting equal
-        # values of the tuple that are not the same types being held together in
-        # the constant dict.  So we make the key include the type of each item
-        # in the sequence.
-        if space.is_true(space.isinstance(value, space.w_tuple)):
-            length = space.int_w(space.len(value))
-            key_w = [None]*(length + 2)
-            key_w[0] = value
-            for i in range(1, length + 1):
-                key_w[i] = space.type(space.getitem(value, space.wrap(i - 1)))
-            key_w[-1] = space.w_tuple
-            self.load_const(value, space.newtuple(key_w))
-        else:
-            self.load_const(value)
+        self.load_const(const.value)
 
     def visit_UnaryOp(self, op):
         self.update_position(op.lineno)

diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -204,49 +204,61 @@
             container[name] = index
         return index
 
-    def add_const(self, obj, w_key=None):
+    def add_const(self, obj):
         """Add a W_Root to the constant array and return its location."""
         space = self.space
-        # To avoid confusing equal but separate types, we hash store the type of
-        # the constant in the dictionary.
-        if w_key is None:
-            # We have to keep the difference between -0.0 and 0.0 floats.
-            w_type = space.type(obj)
-            if space.is_w(w_type, space.w_float):
-                val = space.float_w(obj)
-                if val == 0.0 and rarithmetic.copysign(1., val) < 0:
-                    w_key = space.newtuple([obj, space.w_float, space.w_None])
-                else:
-                    w_key = space.newtuple([obj, space.w_float])
-            elif space.is_w(w_type, space.w_complex):
-                w_real = space.getattr(obj, space.wrap("real"))
-                w_imag = space.getattr(obj, space.wrap("imag"))
-                real = space.float_w(w_real)
-                imag = space.float_w(w_imag)
-                real_negzero = (real == 0.0 and
-                                rarithmetic.copysign(1., real) < 0)
-                imag_negzero = (imag == 0.0 and
-                                rarithmetic.copysign(1., imag) < 0)
-                if real_negzero and imag_negzero:
-                    tup = [obj, space.w_complex, space.w_None, space.w_None,
-                           space.w_None]
-                elif imag_negzero:
-                    tup = [obj, space.w_complex, space.w_None, space.w_None]
-                elif real_negzero:
-                    tup = [obj, space.w_complex, space.w_None]
-                else:
-                    tup = [obj, space.w_complex]
-                w_key = space.newtuple(tup)
-            else:
-                w_key = space.newtuple([obj, w_type])
+        # To avoid confusing equal but separate types, we hash store the type
+        # of the constant in the dictionary.  Moreover, we have to keep the
+        # difference between -0.0 and 0.0 floats, and this recursively in
+        # tuples.
+        w_key = self._make_key(obj)
+
         w_len = space.finditem(self.w_consts, w_key)
         if w_len is None:
             w_len = space.len(self.w_consts)
             space.setitem(self.w_consts, w_key, w_len)
         return space.int_w(w_len)
 
-    def load_const(self, obj, w_key=None):
-        index = self.add_const(obj, w_key)
+    def _make_key(self, obj):
+        # see the tests 'test_zeros_not_mixed*' in ../test/test_compiler.py
+        space = self.space
+        w_type = space.type(obj)
+        if space.is_w(w_type, space.w_float):
+            val = space.float_w(obj)
+            if val == 0.0 and rarithmetic.copysign(1., val) < 0:
+                w_key = space.newtuple([obj, space.w_float, space.w_None])
+            else:
+                w_key = space.newtuple([obj, space.w_float])
+        elif space.is_w(w_type, space.w_complex):
+            w_real = space.getattr(obj, space.wrap("real"))
+            w_imag = space.getattr(obj, space.wrap("imag"))
+            real = space.float_w(w_real)
+            imag = space.float_w(w_imag)
+            real_negzero = (real == 0.0 and
+                            rarithmetic.copysign(1., real) < 0)
+            imag_negzero = (imag == 0.0 and
+                            rarithmetic.copysign(1., imag) < 0)
+            if real_negzero and imag_negzero:
+                tup = [obj, space.w_complex, space.w_None, space.w_None,
+                       space.w_None]
+            elif imag_negzero:
+                tup = [obj, space.w_complex, space.w_None, space.w_None]
+            elif real_negzero:
+                tup = [obj, space.w_complex, space.w_None]
+            else:
+                tup = [obj, space.w_complex]
+            w_key = space.newtuple(tup)
+        elif space.is_w(w_type, space.w_tuple):
+            result_w = [obj, w_type]
+            for w_item in space.fixedview(obj):
+                result_w.append(self._make_key(w_item))
+            w_key = space.newtuple(result_w[:])
+        else:
+            w_key = space.newtuple([obj, w_type])
+        return w_key
+
+    def load_const(self, obj):
+        index = self.add_const(obj)
         self.emit_op_arg(ops.LOAD_CONST, index)
 
     def update_position(self, lineno, force=False):

diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -714,17 +714,42 @@
 
 class AppTestCompiler:
 
+    def test_values_of_different_types(self):
+        exec "a = 0; b = 0L; c = 0.0; d = 0j"
+        assert type(a) is int
+        assert type(b) is long
+        assert type(c) is float
+        assert type(d) is complex
+
+    def test_values_of_different_types_in_tuples(self):
+        exec "a = ((0,),); b = ((0L,),); c = ((0.0,),); d = ((0j,),)"
+        assert type(a[0][0]) is int
+        assert type(b[0][0]) is long
+        assert type(c[0][0]) is float
+        assert type(d[0][0]) is complex
+
     def test_zeros_not_mixed(self):
         import math
         code = compile("x = -0.0; y = 0.0", "<test>", "exec")
         consts = code.co_consts
-        assert len(consts) == 3
-        assert math.copysign(1, consts[0]) != math.copysign(1, consts[1])
+        x, y, z = consts
+        assert isinstance(x, float) and isinstance(y, float)
+        assert math.copysign(1, x) != math.copysign(1, y)
         ns = {}
         exec "z1, z2 = 0j, -0j" in ns
         assert math.atan2(ns["z1"].imag, -1.) == math.atan2(0., -1.)
         assert math.atan2(ns["z2"].imag, -1.) == math.atan2(-0., -1.)
 
+    def test_zeros_not_mixed_in_tuples(self):
+        import math
+        exec "a = (0.0, 0.0); b = (-0.0, 0.0); c = (-0.0, -0.0)"
+        assert math.copysign(1., a[0]) == 1.0
+        assert math.copysign(1., a[1]) == 1.0
+        assert math.copysign(1., b[0]) == -1.0
+        assert math.copysign(1., b[1]) == 1.0
+        assert math.copysign(1., c[0]) == -1.0
+        assert math.copysign(1., c[1]) == -1.0
+
 
 ##class TestPythonAstCompiler(BaseTestCompiler):
 ##    def setup_method(self, method):


More information about the Pypy-commit mailing list