Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit