def is__default(annotator, obj1, obj2): r = SomeBool() s_obj1 = annotator.annotation(obj1) s_obj2 = annotator.annotation(obj2) if s_obj2.is_constant(): if s_obj1.is_constant(): r.const = s_obj1.const is s_obj2.const if s_obj2.const is None and not s_obj1.can_be_none(): r.const = False elif s_obj1.is_constant(): if s_obj1.const is None and not s_obj2.can_be_none(): r.const = False knowntypedata = defaultdict(dict) bk = annotator.bookkeeper def bind(src_obj, tgt_obj): s_src = annotator.annotation(src_obj) s_tgt = annotator.annotation(tgt_obj) if hasattr(s_tgt, 'is_type_of') and s_src.is_constant(): add_knowntypedata( knowntypedata, True, s_tgt.is_type_of, bk.valueoftype(s_src.const)) add_knowntypedata(knowntypedata, True, [tgt_obj], s_src) s_nonnone = s_tgt if (s_src.is_constant() and s_src.const is None and s_tgt.can_be_none()): s_nonnone = s_tgt.nonnoneify() add_knowntypedata(knowntypedata, False, [tgt_obj], s_nonnone) bind(obj2, obj1) bind(obj1, obj2) r.set_knowntypedata(knowntypedata) return r
def is__default(annotator, obj1, obj2): r = SomeBool() s_obj1 = annotator.annotation(obj1) s_obj2 = annotator.annotation(obj2) if s_obj2.is_constant(): if s_obj1.is_constant(): r.const = s_obj1.const is s_obj2.const if s_obj2.const is None and not s_obj1.can_be_none(): r.const = False elif s_obj1.is_constant(): if s_obj1.const is None and not s_obj2.can_be_none(): r.const = False knowntypedata = defaultdict(dict) bk = annotator.bookkeeper def bind(src_obj, tgt_obj): s_src = annotator.annotation(src_obj) s_tgt = annotator.annotation(tgt_obj) if hasattr(s_tgt, 'is_type_of') and s_src.is_constant(): add_knowntypedata(knowntypedata, True, s_tgt.is_type_of, bk.valueoftype(s_src.const)) add_knowntypedata(knowntypedata, True, [tgt_obj], s_src) s_nonnone = s_tgt if (s_src.is_constant() and s_src.const is None and s_tgt.can_be_none()): s_nonnone = s_tgt.nonnoneify() add_knowntypedata(knowntypedata, False, [tgt_obj], s_nonnone) bind(obj2, obj1) bind(obj1, obj2) r.set_knowntypedata(knowntypedata) return r
def compute_result_annotation(self, s_cls): from rpython.annotator.model import SomeBool, SomePBC, SomeInstance r = SomeBool() assert s_cls.is_constant() if isinstance(s_cls, SomePBC): r.const = inspect.isclass(s_cls.const) elif isinstance(s_cls, SomeInstance): r.const = False else: assert False return r
def or_((boo1, boo2)): s = SomeBool() if boo1.is_constant(): if boo1.const: s.const = True else: return boo2 if boo2.is_constant(): if boo2.const: s.const = True return s
def and_((boo1, boo2)): s = SomeBool() if boo1.is_constant(): if not boo1.const: s.const = False else: return boo2 if boo2.is_constant(): if not boo2.const: s.const = False return s
def builtin_hasattr(s_obj, s_attr): if not s_attr.is_constant() or not isinstance(s_attr.const, str): getbookkeeper().warning("hasattr(%r, %r) is not RPythonic enough" % (s_obj, s_attr)) r = SomeBool() if s_obj.is_immutable_constant(): r.const = hasattr(s_obj.const, s_attr.const) elif isinstance(s_obj, SomePBC) and s_obj.getKind() is description.FrozenDesc: answers = {} for d in s_obj.descriptions: answer = d.s_read_attribute(s_attr.const) != s_ImpossibleValue answers[answer] = True if len(answers) == 1: r.const, = answers return r
def contains_SomeDict(annotator, dct, element): annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) if annotator.annotation(dct)._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool
def contains_SomeNone(annotator, obj, element): # return False here for the case "... in None", because it can be later # generalized to "... in d" where d is either None or the empty dict # (which would also return the constant False) s_bool = SomeBool() s_bool.const = False return s_bool
def _compare_helper(annotator, int1, int2): r = SomeBool() s_int1, s_int2 = annotator.annotation(int1), annotator.annotation(int2) if s_int1.is_immutable_constant() and s_int2.is_immutable_constant(): r.const = cmp_op.pyfunc(s_int1.const, s_int2.const) # # The rest of the code propagates nonneg information between # the two arguments. # # Doing the right thing when int1 or int2 change from signed # to unsigned (r_uint) is almost impossible. See test_intcmp_bug. # Instead, we only deduce constrains on the operands in the # case where they are both signed. In other words, if y is # nonneg then "assert x>=y" will let the annotator know that # x is nonneg too, but it will not work if y is unsigned. # if not (rarithmetic.signedtype(s_int1.knowntype) and rarithmetic.signedtype(s_int2.knowntype)): return r knowntypedata = defaultdict(dict) def tointtype(s_int0): if s_int0.knowntype is bool: return int return s_int0.knowntype if s_int1.nonneg and isinstance(int2, Variable): case = cmp_op.opname in ('lt', 'le', 'eq') add_knowntypedata( knowntypedata, case, [int2], SomeInteger(nonneg=True, knowntype=tointtype(s_int2)))
def dict_contains(s_dct, s_element, position): s_dct.dictdef.generalize_key(s_element) if s_dct._is_empty(position): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool
def builtin_hasattr(s_obj, s_attr): if not s_attr.is_constant() or not isinstance(s_attr.const, str): getbookkeeper().warning('hasattr(%r, %r) is not RPythonic enough' % (s_obj, s_attr)) r = SomeBool() if s_obj.is_immutable_constant(): r.const = hasattr(s_obj.const, s_attr.const) elif (isinstance(s_obj, SomePBC) and s_obj.getKind() is description.FrozenDesc): answers = {} for d in s_obj.descriptions: answer = (d.s_read_attribute(s_attr.const) != s_ImpossibleValue) answers[answer] = True if len(answers) == 1: r.const, = answers return r
def op_contains(self, s_element): self.dictdef.generalize_key(s_element) if self._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool
def _compare_helper(annotator, int1, int2): r = SomeBool() s_int1, s_int2 = annotator.annotation(int1), annotator.annotation(int2) if s_int1.is_immutable_constant() and s_int2.is_immutable_constant(): r.const = cmp_op.pyfunc(s_int1.const, s_int2.const) # # The rest of the code propagates nonneg information between # the two arguments. # # Doing the right thing when int1 or int2 change from signed # to unsigned (r_uint) is almost impossible. See test_intcmp_bug. # Instead, we only deduce constrains on the operands in the # case where they are both signed. In other words, if y is # nonneg then "assert x>=y" will let the annotator know that # x is nonneg too, but it will not work if y is unsigned. # if not (rarithmetic.signedtype(s_int1.knowntype) and rarithmetic.signedtype(s_int2.knowntype)): return r knowntypedata = defaultdict(dict) def tointtype(s_int0): if s_int0.knowntype is bool: return int return s_int0.knowntype if s_int1.nonneg and isinstance(int2, Variable): case = cmp_op.opname in ('lt', 'le', 'eq') add_knowntypedata(knowntypedata, case, [int2], SomeInteger(nonneg=True, knowntype=tointtype(s_int2))) if s_int2.nonneg and isinstance(int1, Variable): case = cmp_op.opname in ('gt', 'ge', 'eq') add_knowntypedata(knowntypedata, case, [int1], SomeInteger(nonneg=True, knowntype=tointtype(s_int1))) r.set_knowntypedata(knowntypedata) # a special case for 'x < 0' or 'x >= 0', # where 0 is a flow graph Constant # (in this case we are sure that it cannot become a r_uint later) if (isinstance(int2, Constant) and type(int2.value) is int and # filter out Symbolics int2.value == 0): if s_int1.nonneg: if cmp_op.opname == 'lt': r.const = False if cmp_op.opname == 'ge': r.const = True return r
def union((boo1, boo2)): s = SomeBool() if getattr(boo1, 'const', -1) == getattr(boo2, 'const', -2): s.const = boo1.const if hasattr(boo1, 'knowntypedata') and \ hasattr(boo2, 'knowntypedata'): ktd = merge_knowntypedata(boo1.knowntypedata, boo2.knowntypedata) s.set_knowntypedata(ktd) return s
def is_((obj1, obj2)): r = SomeBool() if obj2.is_constant(): if obj1.is_constant(): r.const = obj1.const is obj2.const if obj2.const is None and not obj1.can_be_none(): r.const = False elif obj1.is_constant(): if obj1.const is None and not obj2.can_be_none(): r.const = False # XXX HACK HACK HACK # XXX HACK HACK HACK # XXX HACK HACK HACK bk = getbookkeeper() if bk is not None: # for testing op = bk._find_current_op("is_", 2) knowntypedata = {} annotator = bk.annotator def bind(src_obj, tgt_obj, tgt_arg): if hasattr(tgt_obj, 'is_type_of') and src_obj.is_constant(): add_knowntypedata(knowntypedata, True, tgt_obj.is_type_of, bk.valueoftype(src_obj.const)) assert annotator.binding(op.args[tgt_arg]) == tgt_obj add_knowntypedata(knowntypedata, True, [op.args[tgt_arg]], src_obj) nonnone_obj = tgt_obj if src_obj.is_constant() and src_obj.const is None and tgt_obj.can_be_none(): nonnone_obj = tgt_obj.nonnoneify() add_knowntypedata(knowntypedata, False, [op.args[tgt_arg]], nonnone_obj) bind(obj2, obj1, 0) bind(obj1, obj2, 1) r.set_knowntypedata(knowntypedata) return r
def s_isinstance(annotator, s_obj, s_type, variables): if not s_type.is_constant(): return SomeBool() r = SomeBool() typ = s_type.const bk = annotator.bookkeeper if s_obj.is_constant(): r.const = isinstance(s_obj.const, typ) elif our_issubclass(bk, s_obj.knowntype, typ): if not s_obj.can_be_none(): r.const = True elif not our_issubclass(bk, typ, s_obj.knowntype): r.const = False elif s_obj.knowntype == int and typ == bool: # xxx this will explode in case of generalisation # from bool to int, notice that isinstance( , bool|int) # is quite border case for RPython r.const = False for v in variables: assert v.annotation == s_obj knowntypedata = defaultdict(dict) if not hasattr(typ, '_freeze_') and isinstance(s_type, SomePBC): add_knowntypedata(knowntypedata, True, variables, bk.valueoftype(typ)) r.set_knowntypedata(knowntypedata) return r
def builtin_isinstance(s_obj, s_type, variables=None): r = SomeBool() if s_type.is_constant(): typ = s_type.const if issubclass(typ, rpython.rlib.rarithmetic.base_int): try: r.const = issubclass(s_obj.knowntype, typ) except TypeError: # s_obj.knowntype is not a Python type at all r.const = False else: if typ == long: getbookkeeper().warning("isinstance(., long) is not RPython") r.const = False return r assert not issubclass(typ, (int, long)) or typ in (bool, int, long), ( "for integers only isinstance(.,int|r_uint) are supported") if s_obj.is_constant(): r.const = isinstance(s_obj.const, typ) elif our_issubclass(s_obj.knowntype, typ): if not s_obj.can_be_none(): r.const = True elif not our_issubclass(typ, s_obj.knowntype): r.const = False elif s_obj.knowntype == int and typ == bool: # xxx this will explode in case of generalisation # from bool to int, notice that isinstance( , bool|int) # is quite border case for RPython r.const = False bk = getbookkeeper() if variables is None: op = bk._find_current_op("simple_call", 3) assert op.args[0] == Constant(isinstance) variables = [op.args[1]] for variable in variables: assert bk.annotator.binding(variable) == s_obj knowntypedata = {} if not hasattr(typ, '_freeze_') and isinstance(s_type, SomePBC): add_knowntypedata(knowntypedata, True, variables, bk.valueoftype(typ)) r.set_knowntypedata(knowntypedata) return r
def xor((boo1, boo2)): s = SomeBool() if boo1.is_constant() and boo2.is_constant(): s.const = boo1.const ^ boo2.const return s
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: # XXX: better error reporting? raise ValueError("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: no_nul = not u'\x00' in x if len(x) == 1: result = SomeUnicodeCodePoint(no_nul=no_nul) else: result = SomeUnicodeString(no_nul=no_nul) 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 OrderedDict or tp is r_ordereddict): key = Constant(x) try: return self.immutable_cache[key] except KeyError: if tp is OrderedDict 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_() classdef = self.getuniqueclassdef(x.__class__) classdef.see_instance(x) result = SomeInstance(classdef) elif x is None: return s_None else: raise Exception("Don't know how to represent %r" % (x,)) result.const = x return result
def bool(self): result = SomeBool() if self.is_constant(): result.const = bool(self.const) return result
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