importtypes,pyfrompypy.objspace.flow.modelimportConstant,FunctionGraphfrompypy.interpreter.pycodeimportcpython_code_signaturefrompypy.interpreter.argumentimportrawshapefrompypy.interpreter.argumentimportArgErrfrompypy.tool.sourcetoolsimportvalid_identifierfrompypy.tool.pairtypeimportextendabletypeclassCallFamily(object):"""A family of Desc objects that could be called from common call sites. The call families are conceptually a partition of all (callable) Desc objects, where the equivalence relation is the transitive closure of 'd1~d2 if d1 and d2 might be called at the same call site'. """overridden=Falsenormalized=Falsemodified=Truedef__init__(self,desc):self.descs={desc:True}self.calltables={}# see calltable_lookup_row()self.total_calltable_size=0defupdate(self,other):self.modified=Trueself.normalized=self.normalizedorother.normalizedself.descs.update(other.descs)forshape,tableinother.calltables.items():forrowintable:self.calltable_add_row(shape,row)absorb=update# UnionFind APIdefcalltable_lookup_row(self,callshape,row):# this code looks up a table of which graph to# call at which call site. Each call site gets a row of graphs,# sharable with other call sites. Each column is a FunctionDesc.# There is one such table per "call shape".table=self.calltables.get(callshape,[])fori,existing_rowinenumerate(table):ifexisting_row==row:# XXX maybe use a dict again here?returniraiseLookupErrordefcalltable_add_row(self,callshape,row):try:self.calltable_lookup_row(callshape,row)exceptLookupError:self.modified=Truetable=self.calltables.setdefault(callshape,[])table.append(row)self.total_calltable_size+=1classFrozenAttrFamily(object):"""A family of FrozenDesc objects that have any common 'getattr' sites. The attr families are conceptually a partition of FrozenDesc objects, where the equivalence relation is the transitive closure of: d1~d2 if d1 and d2 might have some attribute read on them by the same getattr operation. """def__init__(self,desc):self.descs={desc:True}self.read_locations={}# set of position_keysself.attrs={}# { attr: s_value }defupdate(self,other):self.descs.update(other.descs)self.read_locations.update(other.read_locations)self.attrs.update(other.attrs)absorb=update# UnionFind APIdefget_s_value(self,attrname):try:returnself.attrs[attrname]exceptKeyError:frompypy.annotation.modelimports_ImpossibleValuereturns_ImpossibleValuedefset_s_value(self,attrname,s_value):self.attrs[attrname]=s_valueclassClassAttrFamily(object):"""A family of ClassDesc objects that have common 'getattr' sites for a given attribute name. The attr families are conceptually a partition of ClassDesc objects, where the equivalence relation is the transitive closure of: d1~d2 if d1 and d2 might have a common attribute 'attrname' read on them by the same getattr operation. The 'attrname' is not explicitly stored here, but is the key used in the dictionary bookkeeper.pbc_maximal_access_sets_map. """# The difference between ClassAttrFamily and FrozenAttrFamily is that# FrozenAttrFamily is the union for all attribute names, but# ClassAttrFamily is more precise: it is only about one attribut name.def__init__(self,desc):frompypy.annotation.modelimports_ImpossibleValueself.descs={desc:True}self.read_locations={}# set of position_keysself.s_value=s_ImpossibleValue# union of possible valuesdefupdate(self,other):frompypy.annotation.modelimportunionofself.descs.update(other.descs)self.read_locations.update(other.read_locations)self.s_value=unionof(self.s_value,other.s_value)absorb=update# UnionFind APIdefget_s_value(self,attrname):returnself.s_valuedefset_s_value(self,attrname,s_value):self.s_value=s_value# ____________________________________________________________classDesc(object):__metaclass__=extendabletypedef__init__(self,bookkeeper,pyobj=None):self.bookkeeper=bookkeeper# 'pyobj' is non-None if there is an associated underlying Python objself.pyobj=pyobjdef__repr__(self):pyobj=self.pyobjifpyobjisNone:returnobject.__repr__(self)return'<%s for %r>'%(self.__class__.__name__,pyobj)defquerycallfamily(self):"""Retrieve the CallFamily object if there is one, otherwise return None."""call_families=self.bookkeeper.pbc_maximal_call_familiestry:returncall_families[self]exceptKeyError:returnNonedefgetcallfamily(self):"""Get the CallFamily object. Possibly creates one."""call_families=self.bookkeeper.pbc_maximal_call_families_,_,callfamily=call_families.find(self.rowkey())returncallfamilydefmergecallfamilies(self,*others):"""Merge the call families of the given Descs into one."""call_families=self.bookkeeper.pbc_maximal_call_familieschanged,rep,callfamily=call_families.find(self.rowkey())fordescinothers:changed1,rep,callfamily=call_families.union(rep,desc.rowkey())changed=changedorchanged1returnchangeddefqueryattrfamily(self):# no attributes supported by default;# overriden in FrozenDesc and ClassDescreturnNonedefbind_under(self,classdef,name):returnselfdefsimplify_desc_set(descs):passsimplify_desc_set=staticmethod(simplify_desc_set)classNoStandardGraph(Exception):"""The function doesn't have a single standard non-specialized graph."""classFunctionDesc(Desc):knowntype=types.FunctionTypeoverridden=Falsedef__init__(self,bookkeeper,pyobj=None,name=None,signature=None,defaults=None,specializer=None):super(FunctionDesc,self).__init__(bookkeeper,pyobj)ifnameisNone:name=pyobj.func_nameifsignatureisNone:ifhasattr(pyobj,'_generator_next_method_of_'):frompypy.interpreter.argumentimportSignaturesignature=Signature(['entry'])# haaaaaackdefaults=()else:signature=cpython_code_signature(pyobj.func_code)ifdefaultsisNone:defaults=pyobj.func_defaultsself.name=nameself.signature=signatureself.defaults=defaultsor()# 'specializer' is a function with the following signature:# specializer(funcdesc, args_s) => graph# or => s_result (overridden/memo cases)self.specializer=specializerself._cache={}# convenience for the specializerdefbuildgraph(self,alt_name=None,builder=None):translator=self.bookkeeper.annotator.translatorifbuilder:graph=builder(translator,self.pyobj)else:graph=translator.buildflowgraph(self.pyobj)ifalt_name:graph.name=alt_namereturngraphdefgetgraphs(self):returnself._cache.values()defgetuniquegraph(self):iflen(self._cache)!=1:raiseNoStandardGraph(self)[graph]=self._cache.values()relax_sig_check=getattr(self.pyobj,"relax_sig_check",False)if(graph.signature!=self.signatureorgraph.defaults!=self.defaults)andnotrelax_sig_check:raiseNoStandardGraph(self)returngraphdefcachedgraph(self,key,alt_name=None,builder=None):try:returnself._cache[key]exceptKeyError:defnameof(thing):ifisinstance(thing,str):returnthingelifhasattr(thing,'__name__'):# mostly types and functionsreturnthing.__name__elifhasattr(thing,'name')andisinstance(thing.name,str):returnthing.name# mostly ClassDescselifisinstance(thing,tuple):return'_'.join(map(nameof,thing))else:returnstr(thing)[:30]ifkeyisnotNoneandalt_nameisNone:postfix=valid_identifier(nameof(key))alt_name="%s__%s"%(self.name,postfix)graph=self.buildgraph(alt_name,builder)self._cache[key]=graphreturngraphdefparse_arguments(self,args,graph=None):defs_s=[]ifgraphisNone:signature=self.signaturedefaults=self.defaultselse:signature=graph.signaturedefaults=graph.defaultsifdefaults:forxindefaults:defs_s.append(self.bookkeeper.immutablevalue(x))try:inputcells=args.match_signature(signature,defs_s)exceptArgErr,e:raiseTypeError("signature mismatch: %s() %s"%(self.name,e.getmsg()))returninputcellsdefspecialize(self,inputcells,op=None):if(opisNoneandgetattr(self.bookkeeper,"position_key",None)isnotNone):_,block,i=self.bookkeeper.position_keyop=block.operations[i]ifself.specializerisNone:# get the specializer based on the tag of the 'pyobj'# (if any), according to the current policytag=getattr(self.pyobj,'_annspecialcase_',None)policy=self.bookkeeper.annotator.policyself.specializer=policy.get_specializer(tag)enforceargs=getattr(self.pyobj,'_annenforceargs_',None)ifenforceargs:ifnotcallable(enforceargs):frompypy.annotation.policyimportSigenforceargs=Sig(*enforceargs)self.pyobj._annenforceargs_=enforceargsenforceargs(self,inputcells)# can modify inputcells in-placeifgetattr(self.pyobj,'_annspecialcase_','').endswith("call_location"):returnself.specializer(self,inputcells,op)else:returnself.specializer(self,inputcells)defpycall(self,schedule,args,s_previous_result,op=None):inputcells=self.parse_arguments(args)result=self.specialize(inputcells,op)ifisinstance(result,FunctionGraph):graph=result# common case# if that graph has a different signature, we need to re-parse# the arguments.# recreate the args object because inputcells may have been changednew_args=args.unmatch_signature(self.signature,inputcells)inputcells=self.parse_arguments(new_args,graph)result=schedule(graph,inputcells)# Some specializations may break the invariant of returning# annotations that are always more general than the previous time.# We restore it here:frompypy.annotation.modelimportunionofresult=unionof(result,s_previous_result)returnresultdefbind_under(self,classdef,name):# XXX static methodsreturnself.bookkeeper.getmethoddesc(self,classdef,# originclassdef,None,# selfclassdefname)defconsider_call_site(bookkeeper,family,descs,args,s_result,op):shape=rawshape(args)row=FunctionDesc.row_to_consider(descs,args,op)family.calltable_add_row(shape,row)consider_call_site=staticmethod(consider_call_site)defvariant_for_call_site(bookkeeper,family,descs,args,op):shape=rawshape(args)bookkeeper.enter(None)try:row=FunctionDesc.row_to_consider(descs,args,op)finally:bookkeeper.leave()index=family.calltable_lookup_row(shape,row)returnshape,indexvariant_for_call_site=staticmethod(variant_for_call_site)defrowkey(self):returnselfdefrow_to_consider(descs,args,op):# see comments in CallFamilyfrompypy.annotation.modelimports_ImpossibleValuerow={}fordescindescs:defenlist(graph,ignore):row[desc.rowkey()]=graphreturns_ImpossibleValue# meaninglessdesc.pycall(enlist,args,s_ImpossibleValue,op)returnrowrow_to_consider=staticmethod(row_to_consider)defget_s_signatures(self,shape):family=self.getcallfamily()table=family.calltables.get(shape)iftableisNone:return[]else:graph_seen={}s_sigs=[]binding=self.bookkeeper.annotator.bindingdefenlist(graph):ifgraphingraph_seen:returngraph_seen[graph]=Trues_sig=([binding(v)forvingraph.getargs()],binding(graph.getreturnvar()))ifs_sigins_sigs:returns_sigs.append(s_sig)forrowintable:forgraphinrow.itervalues():enlist(graph)returns_sigsNODEFAULT=object()classClassDesc(Desc):knowntype=typeinstance_level=Falseall_enforced_attrs=None# or a setsettled=Falsedef__init__(self,bookkeeper,pyobj=None,name=None,basedesc=None,classdict=None,specialize=None):super(ClassDesc,self).__init__(bookkeeper,pyobj)ifnameisNone:name=pyobj.__module__+'.'+pyobj.__name__self.name=nameself.basedesc=basedescifclassdictisNone:classdict={}# populated belowself.classdict=classdict# {attr: Constant-or-Desc}ifspecializeisNone:specialize=pyobj.__dict__.get('_annspecialcase_','')self.specialize=specializeself._classdefs={}ifpyobjisnotNone:assertpyobj.__module__!='__builtin__'cls=pyobjbase=objectbaselist=list(cls.__bases__)# special case: skip BaseException in Python 2.5, and pretend# that all exceptions ultimately inherit from Exception instead# of BaseException (XXX hack)ifclsisException:baselist=[]elifbaselist==[py.builtin.BaseException]:baselist=[Exception]mixins_before=[]mixins_after=[]forb1inbaselist:ifb1isobject:continueifb1.__dict__.get('_mixin_',False):ifbaseisobject:mixins_before.append(b1)else:mixins_after.append(b1)else:assertbaseisobject,("multiple inheritance only supported ""with _mixin_: %r"%(cls,))base=b1ifmixins_beforeandmixins_after:raiseException("unsupported: class %r has mixin bases both"" before and after the regular base"%(self,))self.add_mixins(mixins_after,check_not_in=base)self.add_mixins(mixins_before)self.add_sources_for_class(cls)ifbaseisnotobject:self.basedesc=bookkeeper.getdesc(base)if'_settled_'incls.__dict__:self.settled=bool(cls.__dict__['_settled_'])if'__slots__'incls.__dict__or'_attrs_'incls.__dict__:attrs={}fordeclin('__slots__','_attrs_'):decl=cls.__dict__.get(decl,[])ifisinstance(decl,str):decl=(decl,)decl=dict.fromkeys(decl)attrs.update(decl)ifself.basedescisnotNone:ifself.basedesc.all_enforced_attrsisNone:raiseException("%r has slots or _attrs_, ""but not its base class"%(pyobj,))attrs.update(self.basedesc.all_enforced_attrs)self.all_enforced_attrs=attrsif(self.is_builtin_exception_class()andself.all_enforced_attrsisNone):frompypy.annotationimportclassdefifself.pyobjnotinclassdef.FORCE_ATTRIBUTES_INTO_CLASSES:self.all_enforced_attrs=[]# no attribute alloweddefadd_source_attribute(self,name,value,mixin=False):ifisinstance(value,types.FunctionType):# for debuggingifnothasattr(value,'class_'):value.class_=self.pyobj# remember that this is really a methodifself.specialize:# make a custom funcdesc that specializes on its first# argument (i.e. 'self').frompypy.annotation.specializeimportspecialize_argtypedefargtype0(funcdesc,args_s):returnspecialize_argtype(funcdesc,args_s,0)funcdesc=FunctionDesc(self.bookkeeper,value,specializer=argtype0)self.classdict[name]=funcdescreturnifmixin:# make a new copy of the FunctionDesc for this class,# but don't specialize further for all subclassesfuncdesc=FunctionDesc(self.bookkeeper,value)self.classdict[name]=funcdescreturn# NB. if value is, say, AssertionError.__init__, then we# should not use getdesc() on it. Never. The problem is# that the py lib has its own AssertionError.__init__ which# is of type FunctionType. But bookkeeper.immutablevalue()# will do the right thing in s_get_value().iftype(value)inMemberDescriptorTypes:# skip __slots__, showing up in the class as 'member' objectsreturnifname=='__init__'andself.is_builtin_exception_class():# pretend that built-in exceptions have no __init__,# unless explicitly specified in builtin.pyfrompypy.annotation.builtinimportBUILTIN_ANALYZERSvalue=getattr(value,'im_func',value)ifvaluenotinBUILTIN_ANALYZERS:returnself.classdict[name]=Constant(value)defadd_mixins(self,mixins,check_not_in=object):ifnotmixins:returnA=type('tmp',tuple(mixins)+(object,),{})mro=A.__mro__assertmro[0]isAandmro[-1]isobjectmro=mro[1:-1]#skip=set()defadd(cls):ifclsisnotobject:forbaseincls.__bases__:add(base)fornameincls.__dict__:skip.add(name)add(check_not_in)#forbaseinreversed(mro):assertbase.__dict__.get("_mixin_",False),("Mixin class %r has non""mixin base class %r"%(mixins,base))forname,valueinbase.__dict__.items():ifnameinskip:continueself.add_source_attribute(name,value,mixin=True)defadd_sources_for_class(self,cls):forname,valueincls.__dict__.items():self.add_source_attribute(name,value)defgetallclassdefs(self):returnself._classdefs.values()defgetclassdef(self,key):try:returnself._classdefs[key]exceptKeyError:frompypy.annotation.classdefimportClassDef,FORCE_ATTRIBUTES_INTO_CLASSESclassdef=ClassDef(self.bookkeeper,self)self.bookkeeper.classdefs.append(classdef)self._classdefs[key]=classdef# forced attributesifself.pyobjisnotNone:cls=self.pyobjifclsinFORCE_ATTRIBUTES_INTO_CLASSES:forname,s_valueinFORCE_ATTRIBUTES_INTO_CLASSES[cls].items():classdef.generalize_attr(name,s_value)classdef.find_attribute(name).modified(classdef)# register all class attributes as coming from this ClassDesc# (as opposed to prebuilt instances)classsources={}forattrinself.classdict:classsources[attr]=self# comes from this ClassDescclassdef.setup(classsources)# look for a __del__ method and annotate it if it's thereif'__del__'inself.classdict:frompypy.annotation.modelimports_None,SomeInstances_func=self.s_read_attribute('__del__')args_s=[SomeInstance(classdef)]s=self.bookkeeper.emulate_pbc_call(classdef,s_func,args_s)asserts_None.contains(s)returnclassdefdefgetuniqueclassdef(self):ifself.specialize:raiseException("not supported on class %r because it needs ""specialization"%(self.name,))returnself.getclassdef(None)defpycall(self,schedule,args,s_previous_result,op=None):frompypy.annotation.modelimportSomeInstance,SomeImpossibleValueifself.specialize:ifself.specialize=='specialize:ctr_location':# We use the SomeInstance annotation returned the last time# to make sure we use the same ClassDef this time.ifisinstance(s_previous_result,SomeInstance):classdef=s_previous_result.classdefelse:classdef=self.getclassdef(object())else:raiseException("unsupported specialization tag: %r"%(self.specialize,))else:classdef=self.getuniqueclassdef()s_instance=SomeInstance(classdef)# look up __init__ directly on the class, bypassing the normal# lookup mechanisms ClassDef (to avoid influencing Attribute placement)s_init=self.s_read_attribute('__init__')ifisinstance(s_init,SomeImpossibleValue):# no __init__: check that there are no constructor argsifnotself.is_exception_class():try:args.fixedunpack(0)exceptValueError:raiseException("default __init__ takes no argument"" (class %s)"%(self.name,))elifself.pyobjisException:# check explicitly against "raise Exception, x" where x# is a low-level exception pointertry:[s_arg]=args.fixedunpack(1)exceptValueError:passelse:frompypy.annotation.modelimportSomePtrassertnotisinstance(s_arg,SomePtr)else:# call the constructorargs=args.prepend(s_instance)s_init.call(args)returns_instancedefis_exception_class(self):returnself.pyobjisnotNoneandissubclass(self.pyobj,py.builtin.BaseException)defis_builtin_exception_class(self):ifself.is_exception_class():ifself.pyobj.__module__=='exceptions':returnTrueifissubclass(self.pyobj,AssertionError):returnTruereturnFalsedeflookup(self,name):cdesc=selfwhilenamenotincdesc.classdict:cdesc=cdesc.basedescifcdescisNone:returnNoneelse:returncdescdefread_attribute(self,name,default=NODEFAULT):cdesc=self.lookup(name)ifcdescisNone:ifdefaultisNODEFAULT:raiseAttributeErrorelse:returndefaultelse:returncdesc.classdict[name]defs_read_attribute(self,name):# look up an attribute in the classcdesc=self.lookup(name)ifcdescisNone:frompypy.annotation.modelimports_ImpossibleValuereturns_ImpossibleValueelse:# delegate to s_get_value to turn it into an annotationreturncdesc.s_get_value(None,name)defs_get_value(self,classdef,name):obj=self.classdict[name]ifisinstance(obj,Constant):value=obj.valueifisinstance(value,staticmethod):# special casevalue=value.__get__(42)classdef=None# don't bindelifisinstance(value,classmethod):raiseAssertionError("classmethods are not supported")s_value=self.bookkeeper.immutablevalue(value)ifclassdefisnotNone:s_value=s_value.bind_callables_under(classdef,name)elifisinstance(obj,Desc):frompypy.annotation.modelimportSomePBCifclassdefisnotNone:obj=obj.bind_under(classdef,name)s_value=SomePBC([obj])else:raiseTypeError("classdict should not contain %r"%(obj,))returns_valuedefcreate_new_attribute(self,name,value):assertnamenotinself.classdict,"name clash: %r"%(name,)self.classdict[name]=Constant(value)deffind_source_for(self,name):ifnameinself.classdict:returnselfifself.pyobjisnotNone:# check whether in the case the classdesc corresponds to a real class# there is a new attributecls=self.pyobjifnameincls.__dict__:self.add_source_attribute(name,cls.__dict__[name])ifnameinself.classdict:returnselfreturnNonedefmaybe_return_immutable_list(self,attr,s_result):# hack: 'x.lst' where lst is listed in _immutable_fields_ as# either 'lst[*]' or 'lst?[*]'# should really return an immutable list as a result. Implemented# by changing the result's annotation (but not, of course, doing an# actual copy in the rtyper). Tested in pypy.rpython.test.test_rlist,# test_immutable_list_out_of_instance.search1='%s[*]'%(attr,)search2='%s?[*]'%(attr,)cdesc=selfwhilecdescisnotNone:if'_immutable_fields_'incdesc.classdict:if(search1incdesc.classdict['_immutable_fields_'].valueorsearch2incdesc.classdict['_immutable_fields_'].value):s_result.listdef.never_resize()s_copy=s_result.listdef.offspring()s_copy.listdef.mark_as_immutable()returns_copycdesc=cdesc.basedescreturns_result# common casedefconsider_call_site(bookkeeper,family,descs,args,s_result,op):frompypy.annotation.modelimportSomeInstance,SomePBC,s_Noneiflen(descs)==1:# call to a single class, look at the result annotation# in case it was specializedifnotisinstance(s_result,SomeInstance):raiseException("calling a class didn't return an instance??")classdefs=[s_result.classdef]else:# call to multiple classes: specialization not supportedclassdefs=[desc.getuniqueclassdef()fordescindescs]# If some of the classes have an __init__ and others not, then# we complain, even though in theory it could work if all the# __init__s take no argument. But it's messy to implement, so# let's just say it is not RPython and you have to add an empty# __init__ to your base class.has_init=Falsefordescindescs:s_init=desc.s_read_attribute('__init__')has_init|=isinstance(s_init,SomePBC)basedesc=ClassDesc.getcommonbase(descs)s_init=basedesc.s_read_attribute('__init__')parent_has_init=isinstance(s_init,SomePBC)ifhas_initandnotparent_has_init:raiseException("some subclasses among %r declare __init__(),"" but not the common parent class"%(descs,))# make a PBC of MethodDescs, one for the __init__ of each classinitdescs=[]fordesc,classdefinzip(descs,classdefs):s_init=desc.s_read_attribute('__init__')ifisinstance(s_init,SomePBC):assertlen(s_init.descriptions)==1,("unexpected dynamic __init__?")initfuncdesc,=s_init.descriptionsifisinstance(initfuncdesc,FunctionDesc):initmethdesc=bookkeeper.getmethoddesc(initfuncdesc,classdef,classdef,'__init__')initdescs.append(initmethdesc)# register a call to exactly these __init__ methodsifinitdescs:initdescs[0].mergecallfamilies(*initdescs[1:])initfamily=initdescs[0].getcallfamily()MethodDesc.consider_call_site(bookkeeper,initfamily,initdescs,args,s_None,op)consider_call_site=staticmethod(consider_call_site)defgetallbases(self):desc=selfwhiledescisnotNone:yielddescdesc=desc.basedescdefgetcommonbase(descs):commondesc=descs[0]fordescindescs[1:]:allbases=set(commondesc.getallbases())whiledescnotinallbases:assertdescisnotNone,"no common base for %r"%(descs,)desc=desc.basedesccommondesc=descreturncommondescgetcommonbase=staticmethod(getcommonbase)defrowkey(self):returnselfdefgetattrfamily(self,attrname):"Get the ClassAttrFamily object for attrname. Possibly creates one."access_sets=self.bookkeeper.get_classpbc_attr_families(attrname)_,_,attrfamily=access_sets.find(self)returnattrfamilydefqueryattrfamily(self,attrname):"""Retrieve the ClassAttrFamily object for attrname if there is one, otherwise return None."""access_sets=self.bookkeeper.get_classpbc_attr_families(attrname)try:returnaccess_sets[self]exceptKeyError:returnNonedefmergeattrfamilies(self,others,attrname):"""Merge the attr families of the given Descs into one."""access_sets=self.bookkeeper.get_classpbc_attr_families(attrname)changed,rep,attrfamily=access_sets.find(self)fordescinothers:changed1,rep,attrfamily=access_sets.union(rep,desc)changed=changedorchanged1returnchangedclassMethodDesc(Desc):knowntype=types.MethodTypedef__init__(self,bookkeeper,funcdesc,originclassdef,selfclassdef,name,flags={}):super(MethodDesc,self).__init__(bookkeeper)self.funcdesc=funcdescself.originclassdef=originclassdefself.selfclassdef=selfclassdefself.name=nameself.flags=flagsdef__repr__(self):ifself.selfclassdefisNone:return'<unbound MethodDesc %r of %r>'%(self.name,self.originclassdef)else:return'<MethodDesc %r of %r bound to %r%r>'%(self.name,self.originclassdef,self.selfclassdef,self.flags)defgetuniquegraph(self):returnself.funcdesc.getuniquegraph()defpycall(self,schedule,args,s_previous_result,op=None):frompypy.annotation.modelimportSomeInstanceifself.selfclassdefisNone:raiseException("calling %r"%(self,))s_instance=SomeInstance(self.selfclassdef,flags=self.flags)args=args.prepend(s_instance)returnself.funcdesc.pycall(schedule,args,s_previous_result,op)defbind_under(self,classdef,name):self.bookkeeper.warning("rebinding an already bound %r"%(self,))returnself.funcdesc.bind_under(classdef,name)defbind_self(self,newselfclassdef,flags={}):returnself.bookkeeper.getmethoddesc(self.funcdesc,self.originclassdef,newselfclassdef,self.name,flags)defconsider_call_site(bookkeeper,family,descs,args,s_result,op):shape=rawshape(args,nextra=1)# account for the extra 'self'funcdescs=[methoddesc.funcdescformethoddescindescs]row=FunctionDesc.row_to_consider(descs,args,op)family.calltable_add_row(shape,row)consider_call_site=staticmethod(consider_call_site)defrowkey(self):# we are computing call families and call tables that always contain# FunctionDescs, not MethodDescs. The present method returns the# FunctionDesc to use as a key in that family.returnself.funcdescdefsimplify_desc_set(descs):# Some hacking needed to make contains() happy on SomePBC: if the# set of MethodDescs contains some "redundant" ones, i.e. ones that# are less general than others already in the set, then kill them.# This ensures that if 'a' is less general than 'b', then# SomePBC({a}) union SomePBC({b}) is again SomePBC({b}).## Two cases:# 1. if two MethodDescs differ in their selfclassdefs, and if one# of the selfclassdefs is a subclass of the other;# 2. if two MethodDescs differ in their flags, take the intersection.# --- case 2 ---# only keep the intersection of all the flags, that's good enoughlst=list(descs)commonflags=lst[0].flags.copy()forkey,valueincommonflags.items():fordescinlst[1:]:ifkeynotindesc.flagsordesc.flags[key]!=value:delcommonflags[key]breakfordescinlst:ifdesc.flags!=commonflags:newdesc=desc.bookkeeper.getmethoddesc(desc.funcdesc,desc.originclassdef,desc.selfclassdef,desc.name,commonflags)descs.remove(desc)descs.add(newdesc)# --- case 1 ---groups={}fordescindescs:ifdesc.selfclassdefisnotNone:key=desc.funcdesc,desc.originclassdef,desc.namegroups.setdefault(key,[]).append(desc)forgroupingroups.values():iflen(group)>1:fordesc1ingroup:cdef1=desc1.selfclassdeffordesc2ingroup:cdef2=desc2.selfclassdefifcdef1isnotcdef2andcdef1.issubclass(cdef2):descs.remove(desc1)breaksimplify_desc_set=staticmethod(simplify_desc_set)defnew_or_old_class(c):ifhasattr(c,'__class__'):returnc.__class__else:returntype(c)classFrozenDesc(Desc):def__init__(self,bookkeeper,pyobj,read_attribute=None):super(FrozenDesc,self).__init__(bookkeeper,pyobj)ifread_attributeisNone:read_attribute=lambdaattr:getattr(pyobj,attr)self._read_attribute=read_attributeself.attrcache={}self.knowntype=new_or_old_class(pyobj)assertbool(pyobj),"__nonzero__ unsupported on frozen PBC %r"%(pyobj,)defhas_attribute(self,attr):ifattrinself.attrcache:returnTruetry:self._read_attribute(attr)returnTrueexceptAttributeError:returnFalsedefwarn_missing_attribute(self,attr):# only warn for missing attribute names whose name doesn't start# with '$', to silence the warnings about '$memofield_xxx'.returnnotself.has_attribute(attr)andnotattr.startswith('$')defread_attribute(self,attr):try:returnself.attrcache[attr]exceptKeyError:result=self.attrcache[attr]=self._read_attribute(attr)returnresultdefs_read_attribute(self,attr):try:value=self.read_attribute(attr)exceptAttributeError:frompypy.annotation.modelimports_ImpossibleValuereturns_ImpossibleValueelse:returnself.bookkeeper.immutablevalue(value)defcreate_new_attribute(self,name,value):try:self.read_attribute(name)exceptAttributeError:passelse:raiseAssertionError("name clash: %r"%(name,))self.attrcache[name]=valuedefgetattrfamily(self,attrname=None):"Get the FrozenAttrFamily object for attrname. Possibly creates one."access_sets=self.bookkeeper.frozenpbc_attr_families_,_,attrfamily=access_sets.find(self)returnattrfamilydefqueryattrfamily(self,attrname=None):"""Retrieve the FrozenAttrFamily object for attrname if there is one, otherwise return None."""access_sets=self.bookkeeper.frozenpbc_attr_familiestry:returnaccess_sets[self]exceptKeyError:returnNonedefmergeattrfamilies(self,others,attrname=None):"""Merge the attr families of the given Descs into one."""access_sets=self.bookkeeper.frozenpbc_attr_familieschanged,rep,attrfamily=access_sets.find(self)fordescinothers:changed1,rep,attrfamily=access_sets.union(rep,desc)changed=changedorchanged1returnchangedclassMethodOfFrozenDesc(Desc):knowntype=types.MethodTypedef__init__(self,bookkeeper,funcdesc,frozendesc):super(MethodOfFrozenDesc,self).__init__(bookkeeper)self.funcdesc=funcdescself.frozendesc=frozendescdef__repr__(self):return'<MethodOfFrozenDesc %r of %r>'%(self.funcdesc,self.frozendesc)defpycall(self,schedule,args,s_previous_result,op=None):frompypy.annotation.modelimportSomePBCs_self=SomePBC([self.frozendesc])args=args.prepend(s_self)returnself.funcdesc.pycall(schedule,args,s_previous_result,op)defconsider_call_site(bookkeeper,family,descs,args,s_result,op):shape=rawshape(args,nextra=1)# account for the extra 'self'funcdescs=[mofdesc.funcdescformofdescindescs]row=FunctionDesc.row_to_consider(descs,args,op)family.calltable_add_row(shape,row)consider_call_site=staticmethod(consider_call_site)defrowkey(self):returnself.funcdesc# ____________________________________________________________classSample(object):__slots__='x'MemberDescriptorTypes=[type(Sample.x)]delSampletry:MemberDescriptorTypes.append(type(OSError.errno))exceptAttributeError:# on CPython <= 2.4pass