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 _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 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 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 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 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 bool_SomeObject(annotator, obj): r = SomeBool() annotator.annotation(obj).bool_behavior(r) s_nonnone_obj = annotator.annotation(obj) if s_nonnone_obj.can_be_none(): s_nonnone_obj = s_nonnone_obj.nonnoneify() knowntypedata = {} add_knowntypedata(knowntypedata, True, [obj], s_nonnone_obj) r.set_knowntypedata(knowntypedata) return r
def contains_String(annotator, string, char): if annotator.annotation(char).is_constant() and annotator.annotation(char).const == "\0": r = SomeBool() knowntypedata = defaultdict(dict) add_knowntypedata(knowntypedata, False, [string], annotator.annotation(string).nonnulify()) r.set_knowntypedata(knowntypedata) return r else: return contains_SomeObject(annotator, string, char)
def contains_String(annotator, string, char): if annotator.annotation(char).is_constant() and annotator.annotation(char).const == "\0": r = SomeBool() knowntypedata = {} add_knowntypedata(knowntypedata, False, [string], annotator.annotation(string).nonnulify()) r.set_knowntypedata(knowntypedata) return r else: return contains_SomeObject(annotator, string, char)
def op_contains(self, s_element): if s_element.is_constant() and s_element.const == "\0": r = SomeBool() bk = getbookkeeper() op = bk._find_current_op(opname="contains", arity=2, pos=0, s_type=self) knowntypedata = {} add_knowntypedata(knowntypedata, False, [op.args[0]], self.nonnulify()) r.set_knowntypedata(knowntypedata) return r else: return SomeObject.op_contains(self, s_element)
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 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 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 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 bool(s_obj): r = SomeBool() s_obj.bool_behavior(r) bk = getbookkeeper() knowntypedata = {} op = bk._find_current_op(opname="bool", arity=1) arg = op.args[0] s_nonnone_obj = s_obj if s_obj.can_be_none(): s_nonnone_obj = s_obj.nonnoneify() add_knowntypedata(knowntypedata, True, [arg], s_nonnone_obj) r.set_knowntypedata(knowntypedata) return r
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 annotationoftype(t, bookkeeper=False): from rpython.rtyper 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 types.NoneType: return s_None elif bookkeeper and extregistry.is_registered_type(t): entry = extregistry.lookup_type(t) return entry.compute_annotation_bk(bookkeeper) elif t is type: return SomeType() elif bookkeeper and not hasattr(t, '_freeze_'): classdef = bookkeeper.getuniqueclassdef(t) return SomeInstance(classdef) else: raise AssertionError("annotationoftype(%r)" % (t, ))
def test_annotation_to_lltype(): s_i = SomeInteger() s_pos = SomeInteger(nonneg=True) s_1 = SomeInteger(nonneg=True) s_1.const = 1 s_m1 = SomeInteger(nonneg=False) s_m1.const = -1 s_u = SomeInteger(nonneg=True, unsigned=True) s_u1 = SomeInteger(nonneg=True, unsigned=True) s_u1.const = r_uint(1) assert annotation_to_lltype(s_i) == lltype.Signed assert annotation_to_lltype(s_pos) == lltype.Signed assert annotation_to_lltype(s_1) == lltype.Signed assert annotation_to_lltype(s_m1) == lltype.Signed assert annotation_to_lltype(s_u) == lltype.Unsigned assert annotation_to_lltype(s_u1) == lltype.Unsigned assert annotation_to_lltype(SomeBool()) == lltype.Bool assert annotation_to_lltype(SomeChar()) == lltype.Char PS = lltype.Ptr(lltype.GcStruct('s')) s_p = SomePtr(ll_ptrtype=PS) assert annotation_to_lltype(s_p) == PS si0 = SomeInstance(DummyClassDef(), True) with py.test.raises(ValueError): annotation_to_lltype(si0) s_singlefloat = SomeSingleFloat() s_singlefloat.const = r_singlefloat(0.0) assert annotation_to_lltype(s_singlefloat) == lltype.SingleFloat
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 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 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 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): r.const = issubclass(s_obj.knowntype, typ) 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 test_ll_to_annotation(): s_z = ll_to_annotation(lltype.Signed._defl()) s_s = SomeInteger() s_u = SomeInteger(nonneg=True, unsigned=True) assert s_z.contains(s_s) assert not s_z.contains(s_u) s_uz = ll_to_annotation(lltype.Unsigned._defl()) assert s_uz.contains(s_u) assert ll_to_annotation(lltype.Bool._defl()).contains(SomeBool()) assert ll_to_annotation(lltype.Char._defl()).contains(SomeChar()) S = lltype.GcStruct('s') A = lltype.GcArray() s_p = ll_to_annotation(lltype.malloc(S)) assert isinstance(s_p, SomePtr) and s_p.ll_ptrtype == lltype.Ptr(S) s_p = ll_to_annotation(lltype.malloc(A, 0)) assert isinstance(s_p, SomePtr) and s_p.ll_ptrtype == lltype.Ptr(A)
def test_str(self): from rpython.annotator.model import SomeBool def f(flag): if flag: x = 'a' else: x = 'brrrrrrr' return len(x + 'a') llinterp, graph = self.llinterpreter_for_transformed_graph(f, [SomeBool()]) res = llinterp.eval_graph(graph, [True]) assert res == f(True) res = llinterp.eval_graph(graph, [False]) assert res == f(False)
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 _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 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 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