def compute_result_annotation(self, s_l, s_sizehint): from rpython.annotator import model as annmodel if annmodel.s_None.contains(s_l): return # first argument is only None so far, but we # expect a generalization later if not isinstance(s_l, annmodel.SomeList): raise annmodel.AnnotatorError("First argument must be a list") if not isinstance(s_sizehint, annmodel.SomeInteger): raise annmodel.AnnotatorError("Second argument must be an integer") s_l.listdef.listitem.resize()
def addpendingblock(self, graph, block, cells): """Register an entry point into block with the given input cells.""" if graph in self.fixed_graphs: # special case for annotating/rtyping in several phases: calling # a graph that has already been rtyped. Safety-check the new # annotations that are passed in, and don't annotate the old # graph -- it's already low-level operations! for a, s_newarg in zip(block.inputargs, cells): s_oldarg = a.annotation # XXX: Should use s_oldarg.contains(s_newarg) but that breaks # PyPy translation if annmodel.unionof(s_oldarg, s_newarg) != s_oldarg: raise annmodel.AnnotatorError( "Late-stage annotation is not allowed to modify the " "existing annotation for variable %s: %s" % (a, s_oldarg)) else: assert not self.frozen if block not in self.annotated: self.bindinputargs(graph, block, cells) else: self.mergeinputargs(graph, block, cells) if not self.annotated[block]: self.pendingblocks[block] = graph
def complete(self): """Process pending blocks until none is left.""" while True: self.complete_pending_blocks() self.policy.no_more_blocks_to_annotate(self) if not self.pendingblocks: break # finished # make sure that the return variables of all graphs is annotated if self.added_blocks is not None: newgraphs = [self.annotated[block] for block in self.added_blocks] newgraphs = dict.fromkeys(newgraphs) got_blocked_blocks = False in newgraphs else: newgraphs = self.translator.graphs #all of them got_blocked_blocks = False in self.annotated.values() if got_blocked_blocks: for graph in self.blocked_graphs.values(): self.blocked_graphs[graph] = True blocked_blocks = [ block for block, done in self.annotated.items() if done is False ] assert len(blocked_blocks) == len(self.blocked_blocks) text = format_blocked_annotation_error(self, self.blocked_blocks) #raise SystemExit() raise annmodel.AnnotatorError(text) for graph in newgraphs: v = graph.getreturnvar() if v.annotation is None: self.setbinding(v, annmodel.s_ImpossibleValue) # policy-dependent computation self.bookkeeper.compute_at_fixpoint()
def getattr(self, s_attr): if not s_attr.is_constant(): raise annmodel.AnnotatorError( "non-constant attr name in getattr()") attrname = s_attr.const TYPE = STAT_FIELD_TYPES[attrname] return lltype_to_annotation(TYPE)
def compute_result_annotation(self, s_l): from rpython.annotator import model as annmodel if annmodel.s_None.contains(s_l): pass # first argument is only None so far, but we # expect a generalization later elif not isinstance(s_l, annmodel.SomeList): raise annmodel.AnnotatorError("First argument must be a list") return annmodel.SomeInteger(nonneg=True)
def complete(self): """Process pending blocks until none is left.""" while True: self.complete_pending_blocks() self.policy.no_more_blocks_to_annotate(self) if not self.pendingblocks: break # finished # make sure that the return variables of all graphs is annotated if self.added_blocks is not None: newgraphs = [self.annotated[block] for block in self.added_blocks] newgraphs = dict.fromkeys(newgraphs) got_blocked_blocks = False in newgraphs else: newgraphs = self.translator.graphs #all of them got_blocked_blocks = False in self.annotated.values() if self.failed_blocks: text = ('Annotation failed, %s errors were recorded:' % len(self.errors)) text += '\n-----'.join(str(e) for e in self.errors) raise annmodel.AnnotatorError(text) if got_blocked_blocks: for graph in self.blocked_graphs.values(): self.blocked_graphs[graph] = True blocked_blocks = [ block for block, done in self.annotated.items() if done is False ] assert len(blocked_blocks) == len(self.blocked_blocks) text = format_blocked_annotation_error(self, self.blocked_blocks) #raise SystemExit() raise annmodel.AnnotatorError(text) for graph in newgraphs: v = graph.getreturnvar() if v.annotation is None: self.setbinding(v, s_ImpossibleValue) v = graph.exceptblock.inputargs[1] if v.annotation is not None and v.annotation.can_be_none(): raise annmodel.AnnotatorError( "%r is found by annotation to possibly raise None, " "but the None was not suppressed by the flow space" % (graph, ))
def getattr(self, s_attr): if not s_attr.is_constant(): raise annmodel.AnnotatorError("non-constant attr name in getattr()") attrname = s_attr.const if attrname in ('st_atime', 'st_mtime', 'st_ctime'): # like CPython, in RPython we can read the st_Xtime # attribute and get a floating-point result. We can also # get a full-precision bigint with get_stat_ns_as_bigint(). # The floating-point result is computed like a property # by _ll_get_st_Xtime(). TYPE = lltype.Float else: TYPE = STAT_FIELD_TYPES[attrname] return lltype_to_annotation(TYPE)
def all_values(s): """Return the exhaustive list of possible values matching annotation `s`. Raises `AnnotatorError` if no such (reasonably small) finite list exists. """ if s.is_constant(): return [s.const] elif isinstance(s, SomePBC): values = [] assert not s.can_be_None, "memo call: cannot mix None and PBCs" for desc in s.descriptions: if desc.pyobj is None: raise annmodel.AnnotatorError( "memo call with a class or PBC that has no " "corresponding Python object (%r)" % (desc, )) values.append(desc.pyobj) return values elif isinstance(s, SomeImpossibleValue): return [] elif isinstance(s, SomeBool): return [False, True] else: raise annmodel.AnnotatorError("memo call: argument must be a class " "or a frozen PBC, got %r" % (s, ))
def specialize_argvalue(funcdesc, args_s, *argindices): from rpython.annotator.model import SomePBC key = [] for i in argindices: s = args_s[i] if s.is_constant(): key.append(s.const) elif isinstance(s, SomePBC) and len(s.descriptions) == 1: # for test_specialize_arg_bound_method desc, = s.descriptions key.append(desc) else: raise annmodel.AnnotatorError("specialize:arg(%d): argument not " "constant: %r" % (i, s)) key = tuple(key) return maybe_star_args(funcdesc, key, args_s)
def memo(funcdesc, args_s): # call the function now, and collect possible results # the list of all possible tuples of arguments to give to the memo function possiblevalues = cartesian_product([all_values(s_arg) for s_arg in args_s]) # a MemoTable factory -- one MemoTable per family of arguments that can # be called together, merged via a UnionFind. bookkeeper = funcdesc.bookkeeper try: memotables = bookkeeper.all_specializations[funcdesc] except KeyError: func = funcdesc.pyobj if func is None: raise annmodel.AnnotatorError( "memo call: no Python function object" "to call (%r)" % (funcdesc, )) def compute_one_result(args): value = func(*args) memotable = MemoTable(funcdesc, args, value) memotable.register_finish() return memotable memotables = UnionFind(compute_one_result) bookkeeper.all_specializations[funcdesc] = memotables # merge the MemoTables for the individual argument combinations firstvalues = possiblevalues.next() _, _, memotable = memotables.find(firstvalues) for values in possiblevalues: _, _, memotable = memotables.union(firstvalues, values) if memotable.graph is not None: return memotable.graph # if already computed else: # otherwise, for now, return the union of each possible result return unionof( *[bookkeeper.immutablevalue(v) for v in memotable.table.values()])
def memo(funcdesc, arglist_s): from rpython.annotator.model import SomePBC, SomeImpossibleValue, SomeBool from rpython.annotator.model import unionof # call the function now, and collect possible results argvalues = [] for s in arglist_s: if s.is_constant(): values = [s.const] elif isinstance(s, SomePBC): values = [] assert not s.can_be_None, "memo call: cannot mix None and PBCs" for desc in s.descriptions: if desc.pyobj is None: raise annmodel.AnnotatorError( "memo call with a class or PBC that has no " "corresponding Python object (%r)" % (desc, )) values.append(desc.pyobj) elif isinstance(s, SomeImpossibleValue): return s # we will probably get more possible args later elif isinstance(s, SomeBool): values = [False, True] else: raise annmodel.AnnotatorError( "memo call: argument must be a class " "or a frozen PBC, got %r" % (s, )) argvalues.append(values) # the list of all possible tuples of arguments to give to the memo function possiblevalues = cartesian_product(argvalues) # a MemoTable factory -- one MemoTable per family of arguments that can # be called together, merged via a UnionFind. bookkeeper = funcdesc.bookkeeper try: memotables = bookkeeper.all_specializations[funcdesc] except KeyError: func = funcdesc.pyobj if func is None: raise annmodel.AnnotatorError( "memo call: no Python function object" "to call (%r)" % (funcdesc, )) def compute_one_result(args): value = func(*args) memotable = MemoTable(funcdesc, args, value) memotable.register_finish() return memotable memotables = UnionFind(compute_one_result) bookkeeper.all_specializations[funcdesc] = memotables # merge the MemoTables for the individual argument combinations firstvalues = possiblevalues.next() _, _, memotable = memotables.find(firstvalues) for values in possiblevalues: _, _, memotable = memotables.union(firstvalues, values) if memotable.graph is not None: return memotable.graph # if already computed else: # otherwise, for now, return the union of each possible result return unionof( *[bookkeeper.immutablevalue(v) for v in memotable.table.values()])