def getclassdef(self, key): try: return self._classdefs[key] except KeyError: from pypy.annotation.classdef import ClassDef, FORCE_ATTRIBUTES_INTO_CLASSES classdef = ClassDef(self.bookkeeper, self) self.bookkeeper.classdefs.append(classdef) self._classdefs[key] = classdef # forced attributes if self.pyobj is not None: cls = self.pyobj if cls in FORCE_ATTRIBUTES_INTO_CLASSES: for name, s_value in FORCE_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 = {} for attr in self.classdict: classsources[attr] = self # comes from this ClassDesc classdef.setup(classsources) # look for a __del__ method and annotate it if it's there if '__del__' in self.classdict: from pypy.annotation.model import s_None, SomeInstance s_func = self.s_read_attribute('__del__') args_s = [SomeInstance(classdef)] s = self.bookkeeper.emulate_pbc_call(classdef, s_func, args_s) assert s_None.contains(s) return classdef
def pycall(self, schedule, args, s_previous_result, op=None): from pypy.annotation.model import SomeInstance if self.selfclassdef is None: raise Exception("calling %r" % (self,)) s_instance = SomeInstance(self.selfclassdef, flags = self.flags) args = args.prepend(s_instance) return self.funcdesc.pycall(schedule, args, s_previous_result, op)
def pycall(self, schedule, args, s_previous_result): from pypy.annotation.model import SomeInstance, SomeImpossibleValue if self.specialize: if self.specialize == 'specialize:ctr_location': # We use the SomeInstance annotation returned the last time # to make sure we use the same ClassDef this time. if isinstance(s_previous_result, SomeInstance): classdef = s_previous_result.classdef else: classdef = self.getclassdef(object()) else: raise Exception("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__') if isinstance(s_init, SomeImpossibleValue): # no __init__: check that there are no constructor args if not self.is_exception_class(): try: args.fixedunpack(0) except ValueError: raise Exception("default __init__ takes no argument" " (class %s)" % (self.name, )) else: # call the constructor args = args.prepend(s_instance) s_init.call(args) return s_instance
def improve((ins1, ins2)): if ins1.classdef is None: resdef = ins2.classdef elif ins2.classdef is None: resdef = ins1.classdef else: basedef = ins1.classdef.commonbase(ins2.classdef) if basedef is ins1.classdef: resdef = ins2.classdef elif basedef is ins2.classdef: resdef = ins1.classdef else: if ins1.can_be_None and ins2.can_be_None: return s_None else: return s_ImpossibleValue res = SomeInstance(resdef, can_be_None=ins1.can_be_None and ins2.can_be_None) if ins1.contains(res) and ins2.contains(res): return res # fine else: # this case can occur in the presence of 'const' attributes, # which we should try to preserve. Fall-back... thistype = pairtype(SomeInstance, SomeInstance) return super(thistype, pair(ins1, ins2)).improve()
def annotationoftype(t, bookkeeper=False): from pypy.rpython import extregistry """The most precise SomeValue instance that contains all objects of type t.""" assert isinstance(t, (type, types.ClassType)) if t is bool: return SomeBool() elif t is int: return SomeInteger() elif t is float: return SomeFloat() elif issubclass(t, str): # py.lib uses annotated str subclasses return SomeString() elif t is unicode: return SomeUnicodeString() elif t is list: return SomeList(MOST_GENERAL_LISTDEF) elif t is dict: return SomeDict(MOST_GENERAL_DICTDEF) # can't do tuple elif t is types.NoneType: return s_None elif bookkeeper and extregistry.is_registered_type(t, bookkeeper.policy): entry = extregistry.lookup_type(t, bookkeeper.policy) return entry.compute_annotation_bk(bookkeeper) elif bookkeeper and t.__module__ != '__builtin__' and t not in bookkeeper.pbctypes: classdef = bookkeeper.getuniqueclassdef(t) return SomeInstance(classdef) else: o = SomeObject() if t != object: o.knowntype = t return o
def robjmodel_instantiate(s_clspbc): assert isinstance(s_clspbc, SomePBC) clsdef = None more_than_one = len(s_clspbc.descriptions) for desc in s_clspbc.descriptions: cdef = desc.getuniqueclassdef() if more_than_one: getbookkeeper().needs_generic_instantiate[cdef] = True if not clsdef: clsdef = cdef else: clsdef = clsdef.commonbase(cdef) return SomeInstance(clsdef)
def compute_result_annotation(self, x_s, type_s): assert isinstance(x_s, SomeOOInstance) assert isinstance(x_s.ootype, NativeInstance) assert type_s.is_constant() TYPE = type_s.const if isinstance(TYPE, (type, types.ClassType)): # it's a user-defined class, so we return SomeInstance # can_be_None == True because it can always return None, if it fails classdef = self.bookkeeper.getuniqueclassdef(TYPE) return SomeInstance(classdef, can_be_None=True) elif isinstance(TYPE, ootype.StaticMethod): return SomeOOStaticMeth(TYPE) elif isinstance(TYPE, ootype.OOType): return SomeOOInstance(TYPE) else: assert TYPE in BOXABLE_TYPES return OverloadingResolver.lltype_to_annotation(TYPE)
def union((ins1, ins2)): if ins1.classdef is None or ins2.classdef is None: # special case only basedef = None else: basedef = ins1.classdef.commonbase(ins2.classdef) if basedef is None: # print warning? return SomeObject() flags = ins1.flags if flags: flags = flags.copy() for key, value in flags.items(): if key not in ins2.flags or ins2.flags[key] != value: del flags[key] return SomeInstance(basedef, can_be_None=ins1.can_be_None or ins2.can_be_None, flags=flags)
def immutablevalue(self, x, need_const=True): """The most precise SomeValue instance that contains the immutable value x.""" # convert unbound methods to the underlying function if hasattr(x, 'im_self') and x.im_self is None: x = x.im_func assert not hasattr(x, 'im_self') if x is sys: # special case constant sys to someobject return SomeObject() tp = type(x) if issubclass(tp, Symbolic): # symbolic constants support result = x.annotation() result.const_box = Constant(x) return result if tp is bool: result = SomeBool() elif tp is int: result = SomeInteger(nonneg=x >= 0) elif tp is long: if -sys.maxint - 1 <= x <= sys.maxint: x = int(x) result = SomeInteger(nonneg=x >= 0) else: raise Exception("seeing a prebuilt long (value %s)" % hex(x)) elif issubclass(tp, str): # py.lib uses annotated str subclasses if len(x) == 1: result = SomeChar() else: result = SomeString() elif tp is unicode: if len(x) == 1: result = SomeUnicodeCodePoint() else: result = SomeUnicodeString() elif tp is tuple: result = SomeTuple( items=[self.immutablevalue(e, need_const) for e in x]) elif tp is float: result = SomeFloat() elif tp is list: if need_const: key = Constant(x) try: return self.immutable_cache[key] except KeyError: result = SomeList(ListDef(self, s_ImpossibleValue)) self.immutable_cache[key] = result for e in x: result.listdef.generalize(self.immutablevalue(e)) result.const_box = key return result else: listdef = ListDef(self, s_ImpossibleValue) for e in x: listdef.generalize(self.immutablevalue(e, False)) result = SomeList(listdef) elif tp is dict or tp is r_dict: if need_const: key = Constant(x) try: return self.immutable_cache[key] except KeyError: result = SomeDict( DictDef(self, s_ImpossibleValue, s_ImpossibleValue, is_r_dict=tp is r_dict)) self.immutable_cache[key] = result if tp is r_dict: s_eqfn = self.immutablevalue(x.key_eq) s_hashfn = self.immutablevalue(x.key_hash) result.dictdef.dictkey.update_rdict_annotations( s_eqfn, s_hashfn) seen_elements = 0 while seen_elements != len(x): items = x.items() for ek, ev in items: result.dictdef.generalize_key( self.immutablevalue(ek)) result.dictdef.generalize_value( self.immutablevalue(ev)) result.dictdef.seen_prebuilt_key(ek) seen_elements = len(items) # if the dictionary grew during the iteration, # start over again result.const_box = key return result else: dictdef = DictDef(self, s_ImpossibleValue, s_ImpossibleValue, is_r_dict=tp is r_dict) if tp is r_dict: s_eqfn = self.immutablevalue(x.key_eq) s_hashfn = self.immutablevalue(x.key_hash) dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn) for ek, ev in x.iteritems(): dictdef.generalize_key(self.immutablevalue(ek, False)) dictdef.generalize_value(self.immutablevalue(ev, False)) dictdef.seen_prebuilt_key(ek) result = SomeDict(dictdef) elif tp is weakref.ReferenceType: x1 = x() if x1 is None: result = SomeWeakRef(None) # dead weakref else: s1 = self.immutablevalue(x1) assert isinstance(s1, SomeInstance) result = SomeWeakRef(s1.classdef) elif ishashable(x) and x in BUILTIN_ANALYZERS: _module = getattr(x, "__module__", "unknown") result = SomeBuiltin(BUILTIN_ANALYZERS[x], methodname="%s.%s" % (_module, x.__name__)) elif extregistry.is_registered(x, self.policy): entry = extregistry.lookup(x, self.policy) result = entry.compute_annotation_bk(self) elif isinstance(x, lltype._ptr): result = SomePtr(lltype.typeOf(x)) elif isinstance(x, llmemory.fakeaddress): result = SomeAddress() elif isinstance(x, ootype._static_meth): result = SomeOOStaticMeth(ootype.typeOf(x)) elif isinstance(x, ootype._class): result = SomeOOClass(x._INSTANCE) # NB. can be None elif isinstance(x, ootype.instance_impl): # XXX result = SomeOOInstance(ootype.typeOf(x)) elif isinstance(x, (ootype._record, ootype._string)): result = SomeOOInstance(ootype.typeOf(x)) elif isinstance(x, (ootype._object)): result = SomeOOObject() elif callable(x): if hasattr(x, 'im_self') and hasattr(x, 'im_func'): # on top of PyPy, for cases like 'l.append' where 'l' is a # global constant list, the find_method() returns non-None s_self = self.immutablevalue(x.im_self, need_const) result = s_self.find_method(x.im_func.__name__) elif hasattr(x, '__self__') and x.__self__ is not None: # for cases like 'l.append' where 'l' is a global constant list s_self = self.immutablevalue(x.__self__, need_const) result = s_self.find_method(x.__name__) if result is None: result = SomeObject() else: result = None if result is None: if (self.annotator.policy.allow_someobjects and getattr(x, '__module__', None) == '__builtin__' # XXX note that the print support functions are __builtin__ and tp not in (types.FunctionType, types.MethodType)): result = SomeObject() result.knowntype = tp # at least for types this needs to be correct else: result = SomePBC([self.getdesc(x)]) elif hasattr(x, '_freeze_') and x._freeze_(): # user-defined classes can define a method _freeze_(), which # is called when a prebuilt instance is found. If the method # returns True, the instance is considered immutable and becomes # a SomePBC(). Otherwise it's just SomeInstance(). result = SomePBC([self.getdesc(x)]) elif hasattr(x, '__class__') \ and x.__class__.__module__ != '__builtin__': self.see_mutable(x) result = SomeInstance(self.getuniqueclassdef(x.__class__)) elif x is None: return s_None else: result = SomeObject() if need_const: result.const = x return result
def simple_call(s_wrf): if s_wrf.classdef is None: return s_None # known to be a dead weakref else: return SomeInstance(s_wrf.classdef, can_be_None=True)
def compute_result_annotation(self, s_w_obj): cls = self.instance.expecting s_inst = SomeInstance(self.bookkeeper.getuniqueclassdef(cls), can_be_None=True) assert s_inst.contains(s_w_obj) return s_None