[pypy-svn] r20256 - in pypy/branch/somepbc-refactoring/pypy: annotation rpython translator/test
arigo at codespeak.net
arigo at codespeak.net
Fri Nov 25 20:52:59 CET 2005
Author: arigo
Date: Fri Nov 25 20:52:58 2005
New Revision: 20256
Modified:
pypy/branch/somepbc-refactoring/pypy/annotation/bookkeeper.py
pypy/branch/somepbc-refactoring/pypy/annotation/classdef.py
pypy/branch/somepbc-refactoring/pypy/annotation/description.py
pypy/branch/somepbc-refactoring/pypy/annotation/model.py
pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py
pypy/branch/somepbc-refactoring/pypy/translator/test/test_annrpython.py
Log:
(pedronis, arigo)
As shown by an rtyper test, we need to make MethodDesc a bit more complicated.
Now they have an 'originclassdef' for the class they come from, and (when a
getattr occurs) they have a 'selfclassdef' for the class of the instance that
they were read from.
SomePBC.__init__() now takes care of the corner case that makes the annotator
'assert contains()' unhappy.
Incidentally, this allows us to re-enable a disabled test from test_annrpython.
Modified: pypy/branch/somepbc-refactoring/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/annotation/bookkeeper.py (original)
+++ pypy/branch/somepbc-refactoring/pypy/annotation/bookkeeper.py Fri Nov 25 20:52:58 2005
@@ -407,10 +407,12 @@
self.getdesc(pyobj.im_func), # funcdesc
self.getdesc(pyobj.im_self)) # frozendesc
else: # regular method
+ origincls, name = origin_of_meth(pyobj)
result = self.getmethoddesc(
self.getdesc(pyobj.im_func), # funcdesc
- self.getuniqueclassdef(pyobj.im_class), # classdef
- name_of_meth(pyobj))
+ self.getuniqueclassdef(origincls), # originclassdef
+ self.getuniqueclassdef(pyobj.im_class), # selfclassdef
+ name)
else:
# must be a frozen pre-built constant, but let's check
assert pyobj._freeze_()
@@ -425,12 +427,14 @@
self.descs[pyobj] = result
return result
- def getmethoddesc(self, funcdesc, classdef, name):
+ def getmethoddesc(self, funcdesc, originclassdef, selfclassdef, name):
+ key = funcdesc, originclassdef, selfclassdef, name
try:
- return self.methoddescs[funcdesc, classdef, name]
+ return self.methoddescs[key]
except KeyError:
- result = description.MethodDesc(self, funcdesc, classdef, name)
- self.methoddescs[funcdesc, classdef, name] = result
+ result = description.MethodDesc(self, funcdesc, originclassdef,
+ selfclassdef, name)
+ self.methoddescs[key] = result
return result
def valueoftype(self, t):
@@ -561,16 +565,16 @@
def warning(self, msg):
return self.annotator.warning(msg)
-def name_of_meth(boundmeth):
+def origin_of_meth(boundmeth):
func = boundmeth.im_func
candname = func.func_name
for cls in inspect.getmro(boundmeth.im_class):
dict = cls.__dict__
if dict.get(candname) is func:
- return candname
+ return cls, candname
for name, value in dict.iteritems():
if value is func:
- return name
+ return cls, name
raise Exception, "could not match bound-method to attribute name: %r" % (boundmeth,)
def ishashable(x):
Modified: pypy/branch/somepbc-refactoring/pypy/annotation/classdef.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/annotation/classdef.py (original)
+++ pypy/branch/somepbc-refactoring/pypy/annotation/classdef.py Fri Nov 25 20:52:58 2005
@@ -309,7 +309,7 @@
for desc in pbc.descriptions:
if isinstance(desc, description.MethodDesc):
meth = True
- methclassdef = desc.classdef
+ methclassdef = desc.originclassdef
if methclassdef is not self and methclassdef.issubclass(self):
pass # subclasses methods are always candidates
elif self.issubclass(methclassdef):
@@ -323,6 +323,9 @@
# clsdef2.lookup_filter(pbc) (see formal proof...)
else:
continue # not matching
+ # bind the method by giving it a selfclassdef. Use the
+ # more precise subclass that it's coming from.
+ desc = desc.bind_self(methclassdef)
d.append(desc)
if uplookup is not None:
# hack^2, in this case the classdef for uplookup could be the result
@@ -334,7 +337,9 @@
uplookup.attr_sources.setdefault(name, [])
check_for_missing_attrs = True
- d.append(updesc)
+ # add the updesc method, bounding it to the more precise
+ # classdef 'self' instead of its originclassdef
+ d.append(updesc.bind_self(self))
elif meth and name is not None:
check_for_missing_attrs = True
Modified: pypy/branch/somepbc-refactoring/pypy/annotation/description.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/annotation/description.py (original)
+++ pypy/branch/somepbc-refactoring/pypy/annotation/description.py Fri Nov 25 20:52:58 2005
@@ -126,6 +126,10 @@
def bind_under(self, classdef, name):
return self
+ def simplify_desc_set(descs):
+ pass
+ simplify_desc_set = staticmethod(simplify_desc_set)
+
class FunctionDesc(Desc):
knowntype = types.FunctionType
@@ -209,7 +213,10 @@
def bind_under(self, classdef, name):
# XXX static methods
- return self.bookkeeper.getmethoddesc(self, classdef, name)
+ return self.bookkeeper.getmethoddesc(self,
+ classdef, # originclassdef,
+ None, # selfclassdef
+ name)
def consider_call_site(bookkeeper, family, descs, args, s_result):
row = FunctionDesc.row_to_consider(descs, args)
@@ -456,6 +463,7 @@
if isinstance(initfuncdesc, FunctionDesc):
initmethdesc = bookkeeper.getmethoddesc(initfuncdesc,
classdef,
+ classdef,
'__init__')
initdescs.append(initmethdesc)
# register a call to exactly these __init__ methods
@@ -473,25 +481,40 @@
class MethodDesc(Desc):
knowntype = types.MethodType
- def __init__(self, bookkeeper, funcdesc, classdef, name):
+ def __init__(self, bookkeeper, funcdesc, originclassdef,
+ selfclassdef, name):
super(MethodDesc, self).__init__(bookkeeper)
self.funcdesc = funcdesc
- self.classdef = classdef
+ self.originclassdef = originclassdef
+ self.selfclassdef = selfclassdef
self.name = name
def __repr__(self):
- return '<MethodDesc %r of %r>' % (self.funcdesc,
- self.classdef)
+ if self.selfclassdef is None:
+ return '<unbound MethodDesc %r of %r>' % (self.name,
+ self.originclassdef)
+ else:
+ return '<MethodDesc %r of %r bound to %r>' % (self.name,
+ self.originclassdef,
+ self.selfclassdef)
def pycall(self, schedule, args, s_previous_result):
from pypy.annotation.model import SomeInstance
- s_instance = SomeInstance(self.classdef)
+ if self.selfclassdef is None:
+ raise Exception("calling %r" % (self,))
+ s_instance = SomeInstance(self.selfclassdef)
args = args.prepend(s_instance)
return self.funcdesc.pycall(schedule, args, s_previous_result)
def bind_under(self, classdef, name):
self.bookkeeper.warning("rebinding an already bound %r" % (self,))
return self.funcdesc.bind_under(classdef, name)
+
+ def bind_self(self, newselfclassdef):
+ return self.bookkeeper.getmethoddesc(self.funcdesc,
+ self.originclassdef,
+ newselfclassdef,
+ self.name)
def consider_call_site(bookkeeper, family, descs, args, s_result):
funcdescs = [methoddesc.funcdesc for methoddesc in descs]
@@ -506,6 +529,27 @@
# FunctionDescs, not MethodDescs. The present method returns the
# FunctionDesc to use as a key in that family.
return self.funcdesc
+
+ def simplify_desc_set(descs):
+ # if two MethodDescs in the set differ only in their selfclassdefs,
+ # and if one of the selfclassdefs is a subclass of the other, then
+ # we can remove the former. This is not just an optimization but
+ # needed to make contains() happy on SomePBC.
+ groups = {}
+ for desc in descs:
+ if desc.selfclassdef is not None:
+ key = desc.funcdesc, desc.originclassdef, desc.name
+ groups.setdefault(key, []).append(desc)
+ for group in groups.values():
+ if len(group) > 1:
+ for desc1 in group:
+ cdef1 = desc1.selfclassdef
+ for desc2 in group:
+ cdef2 = desc2.selfclassdef
+ if cdef1 is not cdef2 and cdef1.issubclass(cdef2):
+ del descs[desc1]
+ break
+ simplify_desc_set = staticmethod(simplify_desc_set)
def new_or_old_class(c):
Modified: pypy/branch/somepbc-refactoring/pypy/annotation/model.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/annotation/model.py (original)
+++ pypy/branch/somepbc-refactoring/pypy/annotation/model.py Fri Nov 25 20:52:58 2005
@@ -303,7 +303,7 @@
descriptions = dict.fromkeys(descriptions)
self.descriptions = descriptions
self.can_be_None = can_be_None
- self.check()
+ self.simplify()
if self.isNone():
self.knowntype = type(None)
self.const = None
@@ -333,10 +333,14 @@
raise ValueError("no 'kind' on the 'None' PBC")
return kinds.keys()[0]
- def check(self):
+ def simplify(self):
if self.descriptions:
# We check that the set only contains a single kind of Desc instance
- self.getKind()
+ kind = self.getKind()
+ # then we remove unnecessary entries in self.descriptions:
+ # some MethodDescs can be 'shadowed' by others
+ if len(self.descriptions) > 1:
+ kind.simplify_desc_set(self.descriptions)
else:
assert self.can_be_None, "use s_ImpossibleValue"
Modified: pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py (original)
+++ pypy/branch/somepbc-refactoring/pypy/rpython/rpbc.py Fri Nov 25 20:52:58 2005
@@ -417,9 +417,9 @@
return NotImplemented
class AbstractMethodsPBCRepr(Repr):
- """Representation selected for a PBC of the form {func: classdef...}.
- It assumes that all the methods come from the same name in a base
- classdef."""
+ """Representation selected for a PBC of MethodDescs.
+ It assumes that all the methods come from the same name and have
+ been read from instances with a common base."""
def __init__(self, rtyper, s_pbc):
self.rtyper = rtyper
@@ -429,14 +429,19 @@
"bound-method-object or None")
mdescs = s_pbc.descriptions.keys()
methodname = mdescs[0].name
+ classdef = mdescs[0].selfclassdef
for mdesc in mdescs[1:]:
if mdesc.name != methodname:
raise TyperError("cannot find a unique name under which the "
"methods can be found: %r" % (
mdescs,))
+ classdef = classdef.commonbase(mdesc.selfclassdef)
+ if classdef is None:
+ raise TyperError("mixing methods coming from instances of "
+ "classes with no common base: %r" % (mdescs,))
self.methodname = methodname
- self.classdef = mdescs[0].classdef.locate_attribute(methodname)
+ self.classdef = classdef.locate_attribute(methodname)
# the low-level representation is just the bound 'self' argument.
self.s_im_self = annmodel.SomeInstance(self.classdef)
self.r_im_self = rclass.getinstancerepr(rtyper, self.classdef)
Modified: pypy/branch/somepbc-refactoring/pypy/translator/test/test_annrpython.py
==============================================================================
--- pypy/branch/somepbc-refactoring/pypy/translator/test/test_annrpython.py (original)
+++ pypy/branch/somepbc-refactoring/pypy/translator/test/test_annrpython.py Fri Nov 25 20:52:58 2005
@@ -905,7 +905,7 @@
bookkeeper = a.bookkeeper
def fam(meth):
- mdesc = bookkeeper.getmethoddesc(bookkeeper.getdesc(meth.im_func), clsdef(meth.im_class), meth.im_func.func_name)
+ mdesc = bookkeeper.getmethoddesc(bookkeeper.getdesc(meth.im_func), clsdef(meth.im_class), clsdef(meth.im_class), meth.im_func.func_name)
mdesc2 = bookkeeper.immutablevalue(meth.im_func.__get__(meth.im_class(), meth.im_class)).descriptions.keys()[0]
assert mdesc == mdesc2 # sanity check
return mdesc.getcallfamily()
@@ -1468,7 +1468,7 @@
s = a.build_types(f, [float])
assert s.const == "dontknow"
- def MAYBE_test_hidden_method(self):
+ def test_hidden_method(self):
class Base:
def method(self):
return ["should be hidden"]
@@ -1477,7 +1477,7 @@
class A(Base):
def method(self):
return "visible"
- class B(A):
+ class B(A): # note: it's a chain of subclasses
def method(self):
return None
def f(flag):
More information about the Pypy-commit
mailing list