def getclassdef(self, key): try: return self._classdefs[key] except KeyError: from rpython.annotator.classdef import ( ClassDef, FORCE_ATTRIBUTES_INTO_CLASSES) classdef = ClassDef(self.bookkeeper, self) self.bookkeeper.classdefs.append(classdef) self._classdefs[key] = classdef # forced attributes 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 rpython.annotator.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 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 pycall(self, schedule, args, s_previous_result, op=None): from rpython.annotator.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, whence, args, s_previous_result, op=None): from rpython.annotator.model import SomeInstance, SomeImpossibleValue 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, )) elif self.pyobj is Exception: # check explicitly against "raise Exception, x" where x # is a low-level exception pointer try: [s_arg] = args.fixedunpack(1) except ValueError: pass else: from rpython.rtyper.llannotation import SomePtr assert not isinstance(s_arg, SomePtr) else: # call the constructor args = args.prepend(s_instance) s_init.call(args) return s_instance
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 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 get_exception(self, operation): """ Return the annotation for all exceptions that `operation` may raise. """ can_only_throw = operation.get_can_only_throw(self) if can_only_throw is None: return SomeInstance(self.bookkeeper.getuniqueclassdef(Exception)) else: return self.bookkeeper.new_exception(can_only_throw)
def robjmodel_instantiate(s_clspbc, s_nonmovable=None): assert isinstance(s_clspbc, SomePBC) clsdef = None more_than_one = len(s_clspbc.descriptions) > 1 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 TYPE in BOXABLE_TYPES: return OverloadingResolver.lltype_to_annotation(TYPE) elif isinstance(TYPE, ootype.StaticMethod): return SomeOOStaticMeth(TYPE) elif isinstance(TYPE, ootype.OOType): return SomeOOInstance(TYPE) else: assert False
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: raise UnionError(ins1, ins2, "RPython cannot unify instances " "with no common base class") 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 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 "\n\nUnionError will be thrown, basically there are 2 or more classes that are on a same context (variable, function args, or function return) that aren't compatible. Here are their __dict__:" print '\n', ins1.classdef.classdesc.classdict print '\n', ins2.classdef.classdesc.classdict, '\n' raise UnionError(ins1, ins2, "RPython cannot unify instances " "with no common base class") 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 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
def simple_call(self): if self.classdef is None: return s_None # known to be a dead weakref else: return SomeInstance(self.classdef, can_be_None=True)
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 func_args(self, args): from rpython.annotator.model import SomeInstance if self.selfclassdef is None: raise Exception("calling %r" % (self, )) s_instance = SomeInstance(self.selfclassdef, flags=self.flags) return args.prepend(s_instance)