[pypy-svn] r33656 - in pypy/dist/pypy/rpython/ootypesystem: . test

antocuni at codespeak.net antocuni at codespeak.net
Tue Oct 24 15:39:53 CEST 2006


Author: antocuni
Date: Tue Oct 24 15:39:52 2006
New Revision: 33656

Modified:
   pypy/dist/pypy/rpython/ootypesystem/ootype.py
   pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py
   pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py
Log:
Support for automatic upcast when calling overloaded methods.



Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/ootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/ootype.py	Tue Oct 24 15:39:52 2006
@@ -889,14 +889,34 @@
             signatures.add(ARGS)
 
     def _resolve_overloading(self, ARGS):
+        # this overloading resolution algorithm is quite simple:
+        # 1) if there is an exact match between ARGS and meth.ARGS, return meth
+        # 2) if there is *only one* meth such as ARGS can be converted
+        #    to meth.ARGS with one or more upcasts, return meth
+        # 3) otherwise, fail
+        matches = []
         for meth in self._overloadings:
-            # check if one of the overloadings has the correct signature
-            # TODO: this algorithm is quite naive, it doesn't handle
-            # automatic conversions
             METH = meth._TYPE
             if METH.ARGS == ARGS:
-                return meth
-        raise TypeError, 'No suitable overloading found for method'
+                return meth # case 1
+            elif self._check_upcast(ARGS, METH.ARGS):
+                matches.append(meth)
+        if len(matches) == 1:
+            return matches[0]
+        elif len(matches) > 1:
+            raise TypeError, 'More than one method match, please use explicit casts'
+        else:
+            raise TypeError, 'No suitable overloading found for method'
+
+    def _check_upcast(self, ARGS1, ARGS2):
+        if len(ARGS1) != len(ARGS2):
+            return False
+        for ARG1, ARG2 in zip(ARGS1, ARGS2):
+            if not (isinstance(ARG1, Instance) and isinstance(ARG2, Instance)):
+                return False
+            if not isSubclass(ARG1, ARG2):
+                return False
+        return True
 
     def _annotate_overloading(self, args_s):
         ARGS = tuple([self._annotation_to_lltype(arg_s) for arg_s in args_s])

Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_ooann.py	Tue Oct 24 15:39:52 2006
@@ -308,3 +308,25 @@
         return a
     a = RPythonAnnotator()
     assert isinstance(a.build_types(f, []), annmodel.SomeFloat)
+
+def test_overload_upcast():
+    C = Instance("base", ROOT, {}, {
+        'foo': overload(meth(Meth([], Void)),
+                        meth(Meth([ROOT], String)))})
+    def f():
+        c = new(C)
+        return c.foo(c)
+    a = RPythonAnnotator()
+    assert isinstance(a.build_types(f, []), annmodel.SomeString)
+
+def test_overload_upcast_fail():
+    C = Instance("base", ROOT, {}, {})
+    C._add_methods({
+        'foo': overload(meth(Meth([], Signed)),
+                        meth(Meth([ROOT, C], String)),
+                        meth(Meth([C, ROOT], String)))})
+    def f():
+        c = new(C)
+        return c.foo(c)
+    a = RPythonAnnotator()
+    py.test.raises(TypeError, a.build_types, f, [])

Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_ootype.py	Tue Oct 24 15:39:52 2006
@@ -191,6 +191,15 @@
     assert c.m(2, 3) == 8
     assert c.m(2.0) == 6
 
+def test_overloaded_method_upcast():
+    def m(self, dummy):
+        return 42
+    C = Instance("base", ROOT, {}, {
+        'foo': overload(meth(Meth([ROOT], String), _callable=m))})
+    c = new(C)
+    assert c.foo(c) == 42
+
+
 def test_explicit_name_clash():
     C = Instance("test", ROOT, {})
 



More information about the Pypy-commit mailing list