[pypy-svn] r26799 - in pypy/dist/pypy: annotation annotation/test rpython/lltypesystem rpython/ootypesystem rpython/test

arigo at codespeak.net arigo at codespeak.net
Fri May 5 10:55:43 CEST 2006


Author: arigo
Date: Fri May  5 10:55:40 2006
New Revision: 26799

Modified:
   pypy/dist/pypy/annotation/classdef.py
   pypy/dist/pypy/annotation/test/test_annrpython.py
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/ootypesystem/rclass.py
   pypy/dist/pypy/rpython/test/test_rclass.py
Log:
(pedronis, arigo)

Supports reading the __class__ attribute on instances.  The result
is a SomePBC of all possible classes, which is quite different from
what type(x) returns, which is just SomeObject(knowntype=type).

It means that .__class__ should be suitable for expressions like
'y = x.__class__()'.



Modified: pypy/dist/pypy/annotation/classdef.py
==============================================================================
--- pypy/dist/pypy/annotation/classdef.py	(original)
+++ pypy/dist/pypy/annotation/classdef.py	Fri May  5 10:55:40 2006
@@ -67,6 +67,7 @@
     #      instances that have the attribute set will turn off readonly-ness.
 
     def __init__(self, name, bookkeeper):
+        assert name != '__class__'
         self.name = name
         self.bookkeeper = bookkeeper
         self.s_value = SomeImpossibleValue()
@@ -131,10 +132,12 @@
         self.shortname = self.name.split('.')[-1]        
         self.subdefs = []
         self.attr_sources = {}   # {name: list-of-sources}
+        self.read_locations_of__class__ = {}
 
         if classdesc.basedesc:
             self.basedef = classdesc.basedesc.getuniqueclassdef()
             self.basedef.subdefs.append(self)
+            self.basedef.see_new_subclass(self)
         else:
             self.basedef = None
 
@@ -370,6 +373,17 @@
         else:
             return False
 
+    def see_new_subclass(self, classdef):
+        for position in self.read_locations_of__class__:
+            self.bookkeeper.annotator.reflowfromposition(position)
+        if self.basedef is not None:
+            self.basedef.see_new_subclass(classdef)
+
+    def read_attr__class__(self):
+        position = self.bookkeeper.position_key
+        self.read_locations_of__class__[position] = True
+        return SomePBC([subdef.classdesc for subdef in self.getallsubdefs()])
+
     def _freeze_(self):
         raise Exception, "ClassDefs are used as knowntype for instances but cannot be used as immutablevalue arguments directly"
 

Modified: pypy/dist/pypy/annotation/test/test_annrpython.py
==============================================================================
--- pypy/dist/pypy/annotation/test/test_annrpython.py	(original)
+++ pypy/dist/pypy/annotation/test/test_annrpython.py	Fri May  5 10:55:40 2006
@@ -2035,7 +2035,31 @@
         assert isinstance(s.items[0], annmodel.SomeInteger)
         assert isinstance(s.items[1], annmodel.SomeChar)        
         assert isinstance(s.items[2], annmodel.SomeChar)        
-        
+
+    def test___class___attribute(self):
+        class Base(object): pass
+        class A(Base): pass
+        class B(Base): pass
+        class C(A): pass
+        def seelater():
+            C()
+        def f(n):
+            if n == 1:
+                x = A()
+            else:
+                x = B()
+            y = B()
+            result = x.__class__, y.__class__
+            seelater()
+            return result
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [int])
+        assert isinstance(s.items[0], annmodel.SomePBC)
+        assert len(s.items[0].descriptions) == 4
+        assert isinstance(s.items[1], annmodel.SomePBC)
+        assert len(s.items[1].descriptions) == 1
+
 
 def g(n):
     return [0,1,2,n]

Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Fri May  5 10:55:40 2006
@@ -467,6 +467,8 @@
     def getattr(ins, s_attr):
         if s_attr.is_constant() and isinstance(s_attr.const, str):
             attr = s_attr.const
+            if attr == '__class__':
+                return ins.classdef.read_attr__class__()
             attrdef = ins.classdef.find_attribute(attr)
             position = getbookkeeper().position_key
             attrdef.read_locations[position] = True

Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Fri May  5 10:55:40 2006
@@ -519,6 +519,10 @@
     def rtype_getattr(self, hop):
         attr = hop.args_s[1].const
         vinst, vattr = hop.inputargs(self, Void)
+        if attr == '__class__' and hop.r_result.lowleveltype is Void:
+            # special case for when the result of '.__class__' is a constant
+            [desc] = hop.s_result.descriptions
+            return hop.inputconst(Void, desc.pyobj)
         if attr in self.allinstancefields:
             return self.getfield(vinst, attr, hop.llops)
         elif attr in self.rclass.allmethods:

Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/rclass.py	Fri May  5 10:55:40 2006
@@ -355,6 +355,15 @@
                 cname = hop.inputconst(ootype.Void, mangled)
                 return hop.genop("oosend", [cname, v_inst],
                                  resulttype = hop.r_result.lowleveltype)
+        elif attr == '__class__':
+            if hop.r_result.lowleveltype is ootype.Void:
+                # special case for when the result of '.__class__' is constant
+                [desc] = hop.s_result.descriptions
+                return hop.inputconst(ootype.Void, desc.pyobj)
+            else:
+                cmeta = inputconst(ootype.Void, "meta")
+                return hop.genop('oogetfield', [v_inst, cmeta],
+                                 resulttype=CLASSTYPE)
         else:
             raise TyperError("no attribute %r on %r" % (attr, self))
 

Modified: pypy/dist/pypy/rpython/test/test_rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rclass.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rclass.py	Fri May  5 10:55:40 2006
@@ -463,6 +463,30 @@
         res = interpret(f, [], type_system=self.ts)
         assert typeOf(res.item0) == Signed
 
+    def test___class___attribute(self):
+        class Base(object): pass
+        class A(Base): pass
+        class B(Base): pass
+        class C(A): pass
+        def seelater():
+            C()
+        def f(n):
+            if n == 1:
+                x = A()
+            else:
+                x = B()
+            y = B()
+            result = x.__class__, y.__class__
+            seelater()
+            return result
+        def g():
+            cls1, cls2 = f(1)
+            return cls1 is A, cls2 is B
+
+        res = interpret(g, [], type_system=self.ts)
+        assert res.item0
+        assert res.item1
+
 
 class TestLltype(BaseTestRclass):
 



More information about the Pypy-commit mailing list