[pypy-svn] r4326 - in pypy/trunk/src/pypy: annotation translator/test

arigo at codespeak.net arigo at codespeak.net
Sat May 8 14:55:55 CEST 2004


Author: arigo
Date: Sat May  8 14:55:54 2004
New Revision: 4326

Modified:
   pypy/trunk/src/pypy/annotation/binaryop.py
   pypy/trunk/src/pypy/annotation/factory.py
   pypy/trunk/src/pypy/annotation/model.py
   pypy/trunk/src/pypy/annotation/unaryop.py
   pypy/trunk/src/pypy/translator/test/snippet.py
   pypy/trunk/src/pypy/translator/test/test_annrpython.py
Log:
Method calls seem to work reasonably well.  There is no corresponding support
in the code generators, though.  This will probably require some more work to
be able to tell the difference between instance and class attributes.


Modified: pypy/trunk/src/pypy/annotation/binaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/binaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/binaryop.py	Sat May  8 14:55:54 2004
@@ -6,7 +6,7 @@
 from pypy.annotation.model import SomeObject, SomeInteger, SomeBool
 from pypy.annotation.model import SomeString, SomeList
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
-from pypy.annotation.model import SomeInstance, SomeFunction
+from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod
 from pypy.annotation.model import unionof, set, setunion, missing_operation
 from pypy.annotation.factory import BlockedInference, getbookkeeper
 
@@ -134,6 +134,19 @@
         return SomeFunction(setunion(fun1.funcs, fun2.funcs))
 
 
+class __extend__(pairtype(SomeMethod, SomeMethod)):
+
+    def union((met1, met2)):
+        # the union of the two meths dictionaries is a dictionary
+        #   {func: unionof(met1[func], met2[func])}
+        d = met1.meths.copy()
+        for func, s_self in met2.meths.items():
+            if func in d:
+                s_self = unionof(d[func], s_self)
+            d[func] = s_self
+        return SomeMethod(d)
+
+
 class __extend__(pairtype(SomeImpossibleValue, SomeObject)):
     def union((imp1, obj2)):
         return obj2

Modified: pypy/trunk/src/pypy/annotation/factory.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/factory.py	(original)
+++ pypy/trunk/src/pypy/annotation/factory.py	Sat May  8 14:55:54 2004
@@ -7,10 +7,11 @@
 """
 
 from __future__ import generators
+from types import FunctionType
 from pypy.annotation.pairtype import pair
 from pypy.annotation.model import SomeImpossibleValue, SomeList
 from pypy.annotation.model import SomeObject, SomeInstance
-from pypy.annotation.model import unionof
+from pypy.annotation.model import unionof, immutablevalue
 from pypy.interpreter.miscutils import getthreadlocals
 
 
@@ -152,6 +153,17 @@
         self.basedef = bookkeeper.getclassdef(base)
         if self.basedef:
             self.basedef.subdefs[cls] = self
+        # collect the (supposed constant) class attributes
+        s_self = SomeInstance(self)
+        for name, value in cls.__dict__.items():
+            # ignore some special attributes
+            if name.startswith('_') and not isinstance(value, FunctionType):
+                continue
+            # although self.getallfactories() is currently empty,
+            # the following might still invalidate some blocks if it
+            # generalizes existing values in parent classes
+            s_value = immutablevalue(value)
+            self.generalize(name, s_value, bookkeeper)
 
     def __repr__(self):
         return '<ClassDef %s.%s>' % (self.cls.__module__, self.cls.__name__)
@@ -185,9 +197,11 @@
     def generalize(self, attr, s_value, bookkeeper=None):
         # we make sure that an attribute never appears both in a class
         # and in some subclass, in two steps:
-        # (1) assert that the attribute is in no superclass
+        # (1) check if the attribute is already in a superclass
         for clsdef in self.getmro():
-            assert clsdef is self or attr not in clsdef.attrs
+            if attr in clsdef.attrs:
+                self = clsdef   # generalize the parent class instead
+                break
         # (2) remove the attribute from subclasses
         subclass_values = []
         for subdef in self.getallsubdefs():

Modified: pypy/trunk/src/pypy/annotation/model.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/model.py	(original)
+++ pypy/trunk/src/pypy/annotation/model.py	Sat May  8 14:55:54 2004
@@ -28,7 +28,7 @@
 #
 
 
-from types import ClassType, BuiltinFunctionType, FunctionType
+from types import ClassType, BuiltinFunctionType, FunctionType, MethodType
 from pypy.annotation.pairtype import pair, extendabletype
 
 
@@ -106,6 +106,12 @@
     def __init__(self, funcs):
         self.funcs = funcs   # set of functions that this one may be
 
+class SomeMethod(SomeObject):
+    "Stands for a bound Python method (or some method out of a list)."
+    knowntype = MethodType
+    def __init__(self, meths):
+        self.meths = meths   # map {python_function: s_self}
+
 class SomeImpossibleValue(SomeObject):
     """The empty set.  Instances are placeholders for objects that
     will never show up at run-time, e.g. elements of an empty list."""

Modified: pypy/trunk/src/pypy/annotation/unaryop.py
==============================================================================
--- pypy/trunk/src/pypy/annotation/unaryop.py	(original)
+++ pypy/trunk/src/pypy/annotation/unaryop.py	Sat May  8 14:55:54 2004
@@ -7,7 +7,7 @@
 from pypy.annotation.model import SomeString, SomeList
 from pypy.annotation.model import SomeTuple, SomeImpossibleValue
 from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass
-from pypy.annotation.model import SomeFunction
+from pypy.annotation.model import SomeFunction, SomeMethod
 from pypy.annotation.model import immutablevalue, decode_simple_call
 from pypy.annotation.model import unionof, set, setunion, missing_operation
 from pypy.annotation.factory import BlockedInference, getbookkeeper
@@ -37,6 +37,9 @@
                 return SomeBuiltin(getattr(obj, 'method_' + attr))
         return SomeObject()
 
+    def get(obj, s_self):
+        return obj   # default __get__ implementation
+
 
 class __extend__(SomeTuple):
 
@@ -61,10 +64,14 @@
     def getattr(ins, s_attr):
         if s_attr.is_constant() and isinstance(s_attr.const, str):
             attr = s_attr.const
+            #print 'getattr:', ins, attr, ins.classdef.revision
             # look for the attribute in the MRO order
             for clsdef in ins.currentdef().getmro():
                 if attr in clsdef.attrs:
-                    return clsdef.attrs[attr]
+                    # XXX we can't see the difference between function objects
+                    # XXX on classes or on instances, so this will incorrectly
+                    # XXX turn functions read from instances into methods
+                    return clsdef.attrs[attr].get(ins)
             # maybe the attribute exists in some subclass? if so, lift it
             clsdef = ins.classdef
             clsdef.generalize(attr, SomeImpossibleValue(), getbookkeeper())
@@ -117,3 +124,21 @@
         factory = getbookkeeper().getfactory(FuncCallFactory)
         results = [factory.pycall(func, arglist) for func in fun.funcs]
         return unionof(*results)
+
+    def get(fun, s_self):    # function -> bound method
+        d = {}
+        for func in fun.funcs:
+            d[func] = s_self
+        return SomeMethod(d)
+
+
+class __extend__(SomeMethod):
+
+    def call(met, args, kwds):
+        arglist = decode_simple_call(args, kwds)
+        #print 'methodcall:', met, arglist
+        assert arglist is not None
+        factory = getbookkeeper().getfactory(FuncCallFactory)
+        results = [factory.pycall(func, [s_self] + arglist)
+                   for func, s_self in met.meths.items()]
+        return unionof(*results)

Modified: pypy/trunk/src/pypy/translator/test/snippet.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/snippet.py	(original)
+++ pypy/trunk/src/pypy/translator/test/snippet.py	Sat May  8 14:55:54 2004
@@ -320,3 +320,21 @@
     e = E()
     e.stuff = (3, "world")
     return C().stuff
+
+class F:
+    pass
+class G(F):
+    def m(self, x):
+        return self.m2(x)
+    def m2(self, x):
+        return D(), x
+class H(F):
+    def m(self, y):
+        return E(), y
+
+def methodcall1(cond):
+    if cond:
+        x = G()
+    else:
+        x = H()
+    return x.m(42)

Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py
==============================================================================
--- pypy/trunk/src/pypy/translator/test/test_annrpython.py	(original)
+++ pypy/trunk/src/pypy/translator/test/test_annrpython.py	Sat May  8 14:55:54 2004
@@ -179,6 +179,16 @@
         self.assertEquals(s.knowntype, list)
         self.assertEquals(s.s_item.knowntype, int)
 
+    def test_methodcall1(self):
+        a = RPythonAnnotator()
+        s = a.build_types(snippet.methodcall1, [int])
+        # result should be a tuple of (C, positive_int)
+        self.assertEquals(s.knowntype, tuple)
+        self.assertEquals(len(s.items), 2)
+        self.assertEquals(s.items[0].knowntype, snippet.C)
+        self.assertEquals(s.items[1].knowntype, int)
+        self.assertEquals(s.items[1].nonneg, True)
+
 
 def g(n):
     return [0,1,2,n]


More information about the Pypy-commit mailing list