def s_get_value(self, classdef, name): obj = self.classdict[name] if isinstance(obj, Constant): value = obj.value if isinstance(value, staticmethod): # special case value = value.__get__(42) classdef = None # don't bind elif isinstance(value, classmethod): raise AnnotatorError("classmethods are not supported") s_value = self.bookkeeper.immutablevalue(value) if classdef is not None: s_value = s_value.bind_callables_under(classdef, name) elif isinstance(obj, Desc): if classdef is not None: obj = obj.bind_under(classdef, name) s_value = SomePBC([obj]) else: raise TypeError("classdict should not contain %r" % (obj, )) return s_value
def lookup_filter(self, pbc, name=None, flags={}): """Selects the methods in the pbc that could possibly be seen by a lookup performed on an instance of 'self', removing the ones that cannot appear. """ d = [] uplookup = None updesc = None for desc in pbc.descriptions: # pick methods but ignore already-bound methods, which can come # from an instance attribute if (isinstance(desc, description.MethodDesc) and desc.selfclassdef is None): methclassdef = desc.originclassdef if methclassdef is not self and methclassdef.issubclass(self): pass # subclasses methods are always candidates elif self.issubclass(methclassdef): # upward consider only the best match if uplookup is None or methclassdef.issubclass(uplookup): uplookup = methclassdef updesc = desc continue # for clsdef1 >= clsdef2, we guarantee that # clsdef1.lookup_filter(pbc) includes # 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, flags) d.append(desc) if uplookup is not None: d.append(updesc.bind_self(self, flags)) if d: return SomePBC(d, can_be_None=pbc.can_be_None) elif pbc.can_be_None: return s_None else: return s_ImpossibleValue
def read_attr__class__(self): position = self.bookkeeper.position_key self.read_locations_of__class__[position] = True return SomePBC([subdef.classdesc for subdef in self.getallsubdefs()])
def union((pbc1, pbc2)): d = pbc1.descriptions.copy() d.update(pbc2.descriptions) return SomePBC(d, can_be_None=pbc1.can_be_None or pbc2.can_be_None)
def bind_callables_under(self, classdef, name): d = [desc.bind_under(classdef, name) for desc in self.descriptions] return SomePBC(d, can_be_None=self.can_be_None)
def immutablevalue(self, x): """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') 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 no_nul = not '\x00' in x if len(x) == 1: result = SomeChar(no_nul=no_nul) else: result = SomeString(no_nul=no_nul) elif tp is unicode: if len(x) == 1: result = SomeUnicodeCodePoint() else: result = SomeUnicodeString() elif tp is bytearray: result = SomeByteArray() elif tp is tuple: result = SomeTuple(items=[self.immutablevalue(e) for e in x]) elif tp is float: result = SomeFloat() elif tp is list: 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 elif (tp is dict or tp is r_dict or tp is SomeOrderedDict.knowntype or tp is r_ordereddict): key = Constant(x) try: return self.immutable_cache[key] except KeyError: if tp is SomeOrderedDict.knowntype or tp is r_ordereddict: cls = SomeOrderedDict else: cls = SomeDict is_r_dict = issubclass(tp, r_dict) result = cls( DictDef(self, s_ImpossibleValue, s_ImpossibleValue, is_r_dict=is_r_dict)) self.immutable_cache[key] = result if 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 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 tp is property: return SomeProperty(x) 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): entry = extregistry.lookup(x) result = entry.compute_annotation_bk(self) elif tp is type: result = SomeConstantType(x, self) 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) 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__) result = s_self.find_method(x.__name__) assert result is not None else: result = None if result is None: result = SomePBC([self.getdesc(x)]) elif hasattr(x, '_freeze_'): assert x._freeze_() is True # 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__': if hasattr(x, '_cleanup_'): x._cleanup_() self.see_mutable(x) result = SomeInstance(self.getuniqueclassdef(x.__class__)) elif x is None: return s_None else: raise Exception("Don't know how to represent %r" % (x, )) result.const = x return result
def pycall(self, schedule, args, s_previous_result, op=None): from rpython.annotator.model import SomePBC s_self = SomePBC([self.frozendesc]) args = args.prepend(s_self) return self.funcdesc.pycall(schedule, args, s_previous_result, op)
def func_args(self, args): from rpython.annotator.model import SomePBC s_self = SomePBC([self.frozendesc]) return args.prepend(s_self)