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 newtuple(self, items_s): if items_s == [Ellipsis]: res = SomeObject() # hack to get a SomeObject as the *arg res.from_ellipsis = True return res else: return SomeTuple(items_s)
def newtuple(self, items_s): if len(items_s) == 1 and items_s[0] is Ellipsis: res = SomeObject() # hack to get a SomeObject as the *arg res.from_ellipsis = True return res else: return SomeTuple(items_s)
def union((obj1, obj2)): if obj1 == obj2: return obj1 else: result = SomeObject() if obj1.knowntype == obj2.knowntype and obj1.knowntype != object: result.knowntype = obj1.knowntype is_type_of1 = getattr(obj1, 'is_type_of', None) is_type_of2 = getattr(obj2, 'is_type_of', None) if obj1.is_immutable_constant() and obj2.is_immutable_constant() and obj1.const == obj2.const: result.const = obj1.const is_type_of = {} if is_type_of1: for v in is_type_of1: is_type_of[v] = True if is_type_of2: for v in is_type_of2: is_type_of[v] = True if is_type_of: result.is_type_of = is_type_of.keys() else: if is_type_of1 and is_type_of1 == is_type_of2: result.is_type_of = is_type_of1 # try to preserve the origin of SomeObjects if obj1 == result: result = obj1 elif obj2 == result: result = obj2 unioncheck(result) return result
def getattr(ins, s_attr): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const if attr == '__class__': return ins.classdef.read_attr__class__() attrdef = ins.classdef.find_attribute(attr) position = getbookkeeper().position_key attrdef.read_locations[position] = True s_result = attrdef.getvalue() # hack: if s_result is a set of methods, discard the ones # that can't possibly apply to an instance of ins.classdef. # XXX do it more nicely if isinstance(s_result, SomePBC): s_result = ins.classdef.lookup_filter(s_result, attr, ins.flags) elif isinstance(s_result, SomeImpossibleValue): ins.classdef.check_missing_attribute_update(attr) # blocking is harmless if the attribute is explicitly listed # in the class or a parent class. for basedef in ins.classdef.getmro(): if basedef.classdesc.all_enforced_attrs is not None: if attr in basedef.classdesc.all_enforced_attrs: raise HarmlesslyBlocked("get enforced attr") elif isinstance(s_result, SomeList): s_result = ins.classdef.classdesc.maybe_return_immutable_list( attr, s_result) return s_result return SomeObject()
def len(pbc): if pbc.isNone(): # this None could later be generalized into an empty list, # whose length is the constant 0; so let's tentatively answer 0. return immutablevalue(0) else: return SomeObject() # len() on a pbc? no chance
def len(dct): s_key = dct.dictdef.read_key() s_value = dct.dictdef.read_value() if isinstance(s_key, SomeImpossibleValue) or isinstance( s_value, SomeImpossibleValue): return immutablevalue(0) return SomeObject.len(dct)
def find_method(obj, name): "Look for a special-case implementation for the named method." type_analyser = builtin.EXTERNAL_TYPE_ANALYZERS[obj.knowntype] if name in type_analyser: analyser = type_analyser[name] return SomeBuiltin(analyser, obj, name) return SomeObject.find_method(obj, name)
def getattr(p, s_attr): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const entry = extregistry.lookup_type(p.knowntype) s_value = entry.get_field_annotation(p.knowntype, attr) return s_value else: return SomeObject()
def simple_call(self, *s_args): from pypy.translator.cli.query import get_cli_class DELEGATE = get_cli_class('System.Delegate')._INSTANCE if ootype.isSubclass(self.ootype, DELEGATE): s_invoke = self.getattr(immutablevalue('Invoke')) return s_invoke.simple_call(*s_args) else: # cannot call a non-delegate return SomeObject.simple_call(self, *s_args)
def compute_result_annotation(self, s_obj): if s_None.contains(s_obj): return s_obj assert isinstance(s_obj, (SomeString, SomeUnicodeString)) if s_obj.no_nul: return s_obj new_s_obj = SomeObject.__new__(s_obj.__class__) new_s_obj.__dict__ = s_obj.__dict__.copy() new_s_obj.no_nul = True return new_s_obj
def union((s_wrf1, s_wrf2)): if s_wrf1.classdef is None: basedef = s_wrf2.classdef # s_wrf1 is known to be dead elif s_wrf2.classdef is None: basedef = s_wrf1.classdef # s_wrf2 is known to be dead else: basedef = s_wrf1.classdef.commonbase(s_wrf2.classdef) if basedef is None: # no common base class! complain... return SomeObject() return SomeWeakRef(basedef)
def getattr(p, s_attr): if s_attr.is_constant() and isinstance(s_attr.const, str): # XXX kill with extfunctable.py if p.knowntype in builtin.EXTERNAL_TYPE_ANALYZERS: return SomeObject.getattr(p, s_attr) attr = s_attr.const entry = extregistry.lookup_type(p.knowntype) s_value = entry.get_field_annotation(p.knowntype, attr) return s_value else: return SomeObject()
def union((ext1, ext2)): def commonsuperclass(cls1, cls2): cls = cls2 while not issubclass(cls1, cls): cls = cls.__bases__[0] return cls from pypy.rpython.ootypesystem.bltregistry import BasicExternal cls = commonsuperclass(ext1.knowntype, ext2.knowntype) if cls is BasicExternal: return SomeObject() return SomeExternalInstance(cls)
def union((obj1, obj2)): if obj1 == obj2: return obj1 else: result = SomeObject() if obj1.knowntype == obj2.knowntype and obj1.knowntype != object: result.knowntype = obj1.knowntype is_type_of1 = getattr(obj1, 'is_type_of', None) is_type_of2 = getattr(obj2, 'is_type_of', None) if obj1.is_immutable_constant() and obj2.is_immutable_constant( ) and obj1.const == obj2.const: result.const = obj1.const is_type_of = {} if is_type_of1: for v in is_type_of1: is_type_of[v] = True if is_type_of2: for v in is_type_of2: is_type_of[v] = True if is_type_of: result.is_type_of = is_type_of.keys() else: if is_type_of1 and is_type_of1 == is_type_of2: result.is_type_of = is_type_of1 # try to preserve the origin of SomeObjects if obj1 == result: result = obj1 elif obj2 == result: result = obj2 unioncheck(result) return result
def getattr(s_array, s_attr): s = None if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const if attr == 'shape': s = SomeTuple([SomeInteger()]*s_array.ndim) elif attr == 'ndim': s = SomeInteger() elif attr == 'dtype': s = SomeChar() if s is None: return SomeObject.getattr(s_array, s_attr) return s
def getattr(s_array, s_attr): s = None if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const if attr == 'shape': s = SomeTuple([SomeInteger()] * s_array.ndim) elif attr == 'ndim': s = SomeInteger() elif attr == 'dtype': s = SomeChar() if s is None: return SomeObject.getattr(s_array, s_attr) return s
def getattr(obj, s_attr): # get a SomeBuiltin if the SomeObject has # a corresponding method to handle it if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const s_method = obj.find_method(attr) if s_method is not None: return s_method # if the SomeObject is itself a constant, allow reading its attrs if obj.is_immutable_constant() and hasattr(obj.const, attr): return immutablevalue(getattr(obj.const, attr)) else: getbookkeeper().warning('getattr(%r, %r) is not RPythonic enough' % (obj, s_attr)) return SomeObject()
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 type(obj, *moreargs): if moreargs: raise Exception, 'type() called with more than one argument' if obj.is_constant(): if isinstance(obj, SomeInstance): r = SomePBC([obj.classdef.classdesc]) else: r = immutablevalue(obj.knowntype) else: r = SomeObject() r.knowntype = type bk = getbookkeeper() fn, block, i = bk.position_key annotator = bk.annotator op = block.operations[i] assert op.opname == "type" assert len(op.args) == 1 assert annotator.binding(op.args[0]) == obj r.is_type_of = [op.args[0]] return r
def len(lst): s_item = lst.listdef.read_item() if isinstance(s_item, SomeImpossibleValue): return immutablevalue(0) return SomeObject.len(lst)
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 import_func(*args): return SomeObject()
def builtin_tuple(s_iterable): if isinstance(s_iterable, SomeTuple): return s_iterable return SomeObject()
def long(obj): return SomeObject() # XXX
def union((ext1, ext2)): if ext1.knowntype == ext2.knowntype: return SomeExternalObject(ext1.knowntype) return SomeObject()
def len(p): length = p.ll_ptrtype._example()._fixedlength() if length is None: return SomeObject.len(p) else: return immutablevalue(length)
def call(obj, args, implicit_init=False): #raise Exception, "cannot follow call_args%r" % ((obj, args),) getbookkeeper().warning("cannot follow call(%r, %r)" % (obj, args)) return SomeObject()
def len(dct): s_key = dct.dictdef.read_key() s_value = dct.dictdef.read_value() if isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue): return immutablevalue(0) return SomeObject.len(dct)
def builtin_apply(*stuff): getbookkeeper().warning("ignoring apply%r" % (stuff,)) return SomeObject()
def len(dct): if dct._is_empty(): return immutablevalue(0) return SomeObject.len(dct)
position_key = getbookkeeper().position_key else: position_key = self.bookkeeper.position_key self.dictvalue.read_locations[position_key] = True return self.dictvalue.s_value def same_as(self, other): return (self.dictkey is other.dictkey and self.dictvalue is other.dictvalue) def union(self, other): if (self.same_as(MOST_GENERAL_DICTDEF) or other.same_as(MOST_GENERAL_DICTDEF)): return MOST_GENERAL_DICTDEF # without merging else: self.dictkey.merge(other.dictkey) self.dictvalue.merge(other.dictvalue) return self def generalize_key(self, s_key): self.dictkey.generalize(s_key) def generalize_value(self, s_value): self.dictvalue.generalize(s_value) def __repr__(self): return '<{%r: %r}>' % (self.dictkey.s_value, self.dictvalue.s_value) MOST_GENERAL_DICTDEF = DictDef(None, SomeObject(), SomeObject())
def union((tup1, tup2)): if len(tup1.items) != len(tup2.items): return SomeObject() else: unions = [unioncheck(x, y) for x, y in zip(tup1.items, tup2.items)] return SomeTuple(items=unions)
self.listitem.immutable and 'I' or '', self.listitem.must_not_resize and '!R' or '') def mutate(self): self.listitem.mutate() def resize(self): self.listitem.mutate() self.listitem.resize() def never_resize(self): if self.listitem.resized: raise ListChangeUnallowed("list already resized") self.listitem.must_not_resize = True def mark_as_immutable(self): # Sets the 'immutable' flag. Note that unlike "never resized", # the immutable flag is only a hint. It is cleared again e.g. # when we merge with a "normal" list that doesn't have it. It # is thus expected to live only shortly, mostly for the case # of writing 'x.list[n]'. self.never_resize() if not self.listitem.mutated: self.listitem.immutable = True #else: it's fine, don't set immutable=True at all (see # test_can_merge_immutable_list_with_regular_list) MOST_GENERAL_LISTDEF = ListDef(None, SomeObject()) s_list_of_strings = SomeList(ListDef(None, SomeString(), resized = True))