Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r72401:4bf29ad76462
Date: 2014-07-09 18:01 +0200
http://bitbucket.org/pypy/pypy/changeset/4bf29ad76462/

Log:    Support in RPython fetching the __name__ of a class.

diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4276,6 +4276,15 @@
         py.test.raises(annmodel.AnnotatorError,
                        a.build_types, f, [annmodel.s_None])
 
+    def test_class___name__(self):
+        class Abc(object):
+            pass
+        def f():
+            return Abc().__class__.__name__
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeString)
+
 
 def g(n):
     return [0, 1, 2, n]
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -745,6 +745,11 @@
 class __extend__(SomePBC):
 
     def getattr(self, s_attr):
+        assert s_attr.is_constant()
+        if s_attr.const == '__name__':
+            from rpython.annotator.description import ClassDesc
+            if self.getKind() is ClassDesc:
+                return SomeString()
         bookkeeper = getbookkeeper()
         return bookkeeper.pbc_getattr(self, s_attr)
     getattr.can_only_throw = []
diff --git a/rpython/rtyper/rpbc.py b/rpython/rtyper/rpbc.py
--- a/rpython/rtyper/rpbc.py
+++ b/rpython/rtyper/rpbc.py
@@ -5,7 +5,7 @@
 from rpython.annotator.argument import simple_args
 from rpython.rtyper import rclass, callparse
 from rpython.rtyper.error import TyperError
-from rpython.rtyper.lltypesystem.lltype import typeOf, Void
+from rpython.rtyper.lltypesystem import lltype
 from rpython.rtyper.rmodel import (Repr, inputconst, CanBeNull, mangle,
     warning, impossible_repr)
 from rpython.tool.pairtype import pair, pairtype
@@ -113,7 +113,7 @@
                 llfn = rtyper.getcallable(graph)
                 concreterow[funcdesc] = llfn
             assert len(concreterow) > 0
-            concreterow.fntype = typeOf(llfn)   # 'llfn' from the loop above
+            concreterow.fntype = lltype.typeOf(llfn)# 'llfn' from the loop 
above
                                          # (they should all have the same type)
             concreterows[shape, index] = concreterow
 
@@ -161,7 +161,7 @@
         self.callfamily = s_pbc.any_description().getcallfamily()
         if len(s_pbc.descriptions) == 1 and not s_pbc.can_be_None:
             # a single function
-            self.lowleveltype = Void
+            self.lowleveltype = lltype.Void
         else:
             concretetable, uniquerows = get_concrete_calltable(self.rtyper,
                                                                self.callfamily)
@@ -193,7 +193,7 @@
             return self.funccache[funcdesc]
         except KeyError:
             pass
-        if self.lowleveltype is Void:
+        if self.lowleveltype is lltype.Void:
             result = None
         else:
             llfns = {}
@@ -225,7 +225,7 @@
             value = value.im_func   # unbound method -> bare function
         elif isinstance(value, staticmethod):
             value = value.__get__(42) # hackish, get the function wrapped by 
staticmethod
-        if self.lowleveltype is Void:
+        if self.lowleveltype is lltype.Void:
             return None
         if value is None:
             null = self.rtyper.type_system.null_callable(self.lowleveltype)
@@ -239,27 +239,27 @@
         'index' and 'shape' tells which of its items we are interested in.
         """
         assert v.concretetype == self.lowleveltype
-        if self.lowleveltype is Void:
+        if self.lowleveltype is lltype.Void:
             assert len(self.s_pbc.descriptions) == 1
                                       # lowleveltype wouldn't be Void otherwise
             funcdesc, = self.s_pbc.descriptions
             row_of_one_graph = self.callfamily.calltables[shape][index]
             graph = row_of_one_graph[funcdesc]
             llfn = self.rtyper.getcallable(graph)
-            return inputconst(typeOf(llfn), llfn)
+            return inputconst(lltype.typeOf(llfn), llfn)
         elif len(self.uniquerows) == 1:
             return v
         else:
             # 'v' is a Struct pointer, read the corresponding field
             row = self.concretetable[shape, index]
-            cname = inputconst(Void, row.attrname)
+            cname = inputconst(lltype.Void, row.attrname)
             return self.get_specfunc_row(llop, v, cname, row.fntype)
 
     def get_unique_llfn(self):
         # try to build a unique low-level function.  Avoid to use
         # whenever possible!  Doesn't work with specialization, multiple
         # different call sites, etc.
-        if self.lowleveltype is not Void:
+        if self.lowleveltype is not lltype.Void:
             raise TyperError("cannot pass multiple functions here")
         assert len(self.s_pbc.descriptions) == 1
                                   # lowleveltype wouldn't be Void otherwise
@@ -281,7 +281,7 @@
         if graphs != [graph]*len(graphs):
             raise TyperError("cannot pass a specialized function here")
         llfn = self.rtyper.getcallable(graph)
-        return inputconst(typeOf(llfn), llfn)
+        return inputconst(lltype.typeOf(llfn), llfn)
 
     def get_concrete_llfn(self, s_pbc, args_s, op):
         bk = self.rtyper.annotator.bookkeeper
@@ -293,7 +293,7 @@
         row_of_one_graph = self.callfamily.calltables[shape][index]
         graph = row_of_one_graph[funcdesc]
         llfn = self.rtyper.getcallable(graph)
-        return inputconst(typeOf(llfn), llfn)
+        return inputconst(lltype.typeOf(llfn), llfn)
 
     def rtype_simple_call(self, hop):
         return self.call(hop)
@@ -319,7 +319,7 @@
         if isinstance(vlist[0], Constant):
             v = hop.genop('direct_call', vlist, resulttype = rresult)
         else:
-            vlist.append(hop.inputconst(Void, row_of_graphs.values()))
+            vlist.append(hop.inputconst(lltype.Void, row_of_graphs.values()))
             v = hop.genop('indirect_call', vlist, resulttype = rresult)
         if hop.r_result is impossible_repr:
             return None      # see test_always_raising_methods
@@ -331,10 +331,10 @@
         # this check makes sense because both source and dest repr are 
FunctionsPBCRepr
         if r_fpbc1.lowleveltype == r_fpbc2.lowleveltype:
             return v
-        if r_fpbc1.lowleveltype is Void:
+        if r_fpbc1.lowleveltype is lltype.Void:
             return inputconst(r_fpbc2, r_fpbc1.s_pbc.const)
-        if r_fpbc2.lowleveltype is Void:
-            return inputconst(Void, None)
+        if r_fpbc2.lowleveltype is lltype.Void:
+            return inputconst(lltype.Void, None)
         return NotImplemented
 
 class OverriddenFunctionPBCRepr(Repr):
@@ -342,7 +342,7 @@
         self.rtyper = rtyper
         self.s_pbc = s_pbc
         assert len(s_pbc.descriptions) == 1
-        self.lowleveltype = Void
+        self.lowleveltype = lltype.Void
 
     def rtype_simple_call(self, hop):
         from rpython.rtyper.rspecialcase import rtype_call_specialcase
@@ -377,7 +377,7 @@
 
 class SingleFrozenPBCRepr(Repr):
     """Representation selected for a single non-callable pre-built constant."""
-    lowleveltype = Void
+    lowleveltype = lltype.Void
 
     def __init__(self, frozendesc):
         self.frozendesc = frozendesc
@@ -412,7 +412,7 @@
             return self.converted_pbc_cache[frozendesc]
         except KeyError:
             r = self.rtyper.getrepr(annmodel.SomePBC([frozendesc]))
-            if r.lowleveltype is Void:
+            if r.lowleveltype is lltype.Void:
                 # must create a new empty structure, as a placeholder
                 pbc = self.create_instance()
             else:
@@ -462,7 +462,7 @@
             result = self.create_instance()
             self.pbc_cache[frozendesc] = result
             for attr, (mangled_name, r_value) in self.fieldmap.items():
-                if r_value.lowleveltype is Void:
+                if r_value.lowleveltype is lltype.Void:
                     continue
                 try:
                     thisattrvalue = frozendesc.attrcache[attr]
@@ -479,7 +479,7 @@
             return hop.inputconst(hop.r_result, hop.s_result.const)
 
         attr = hop.args_s[1].const
-        vpbc, vattr = hop.inputargs(self, Void)
+        vpbc, vattr = hop.inputargs(self, lltype.Void)
         v_res = self.getfield(vpbc, attr, hop.llops)
         mangled_name, r_res = self.fieldmap[attr]
         return hop.llops.convertvar(v_res, r_res, hop.r_result)
@@ -503,7 +503,7 @@
 class __extend__(pairtype(AbstractMultipleUnrelatedFrozenPBCRepr,
                           SingleFrozenPBCRepr)):
     def convert_from_to((r_pbc1, r_pbc2), v, llops):
-        return inputconst(Void, r_pbc2.frozendesc)
+        return inputconst(lltype.Void, r_pbc2.frozendesc)
 
 
 class MethodOfFrozenPBCRepr(Repr):
@@ -594,7 +594,7 @@
         #    raise TyperError("unsupported: variable of type "
         #                     "class-pointer or None")
         if s_pbc.is_constant():
-            self.lowleveltype = Void
+            self.lowleveltype = lltype.Void
         else:
             self.lowleveltype = self.getlowleveltype()
 
@@ -617,7 +617,7 @@
     def convert_desc(self, desc):
         if desc not in self.s_pbc.descriptions:
             raise TyperError("%r not in %r" % (desc, self))
-        if self.lowleveltype is Void:
+        if self.lowleveltype is lltype.Void:
             return None
         subclassdef = desc.getuniqueclassdef()
         r_subclass = rclass.getclassrepr(self.rtyper, subclassdef)
@@ -625,7 +625,7 @@
 
     def convert_const(self, cls):
         if cls is None:
-            if self.lowleveltype is Void:
+            if self.lowleveltype is lltype.Void:
                 return None
             else:
                 T = self.lowleveltype
@@ -639,8 +639,15 @@
             return hop.inputconst(hop.r_result, hop.s_result.const)
         else:
             attr = hop.args_s[1].const
+            if attr == '__name__':
+                from rpython.rtyper.lltypesystem import rstr
+                class_repr = rclass.getclassrepr(self.rtyper, None)
+                vcls, vattr = hop.inputargs(class_repr, lltype.Void)
+                cname = inputconst(lltype.Void, 'name')
+                return hop.genop('getfield', [vcls, cname],
+                                 resulttype = lltype.Ptr(rstr.STR))
             access_set, class_repr = self.get_access_set(attr)
-            vcls, vattr = hop.inputargs(class_repr, Void)
+            vcls, vattr = hop.inputargs(class_repr, lltype.Void)
             v_res = class_repr.getpbcfield(vcls, access_set, attr, hop.llops)
             s_res = access_set.s_value
             r_res = self.rtyper.getrepr(s_res)
@@ -669,7 +676,7 @@
 
         if len(self.s_pbc.descriptions) == 1:
             # instantiating a single class
-            if self.lowleveltype is not Void:
+            if self.lowleveltype is not lltype.Void:
                 assert 0, "XXX None-or-1-class instantation not implemented"
             assert isinstance(s_instance, annmodel.SomeInstance)
             classdef = s_instance.classdef
@@ -726,7 +733,7 @@
         # turn a PBC of classes to a standard pointer-to-vtable class repr
         if r_clspbc.lowleveltype == r_cls.lowleveltype:
             return v
-        if r_clspbc.lowleveltype is Void:
+        if r_clspbc.lowleveltype is lltype.Void:
             return inputconst(r_cls, r_clspbc.s_pbc.const)
         # convert from ptr-to-object-vtable to ptr-to-more-precise-vtable
         return r_cls.fromclasstype(v, llops)
@@ -736,10 +743,10 @@
         # this check makes sense because both source and dest repr are 
ClassesPBCRepr
         if r_clspbc1.lowleveltype == r_clspbc2.lowleveltype:
             return v
-        if r_clspbc1.lowleveltype is Void:
+        if r_clspbc1.lowleveltype is lltype.Void:
             return inputconst(r_clspbc2, r_clspbc1.s_pbc.const)
-        if r_clspbc2.lowleveltype is Void:
-            return inputconst(Void, r_clspbc2.s_pbc.const)
+        if r_clspbc2.lowleveltype is lltype.Void:
+            return inputconst(lltype.Void, r_clspbc2.s_pbc.const)
         return NotImplemented
 
 def adjust_shape(hop2, s_shape):
diff --git a/rpython/rtyper/test/test_rpbc.py b/rpython/rtyper/test/test_rpbc.py
--- a/rpython/rtyper/test/test_rpbc.py
+++ b/rpython/rtyper/test/test_rpbc.py
@@ -1642,6 +1642,20 @@
         res = self.interpret(g, [])
         assert res == False
 
+    def test_class___name__(self):
+        class Base(object): pass
+        class ASub(Base): pass
+        def g(n):
+            if n == 1:
+                x = Base()
+            else:
+                x = ASub()
+            return x.__class__.__name__
+        res = self.interpret(g, [1])
+        assert self.ll_to_string(res) == "Base"
+        res = self.interpret(g, [2])
+        assert self.ll_to_string(res) == "ASub"
+
 # ____________________________________________________________
 
 class TestRPBCExtra(BaseRtypingTest):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to