1
from __future__ import generators
3
from types import ClassType, FunctionType
4
from pypy.tool.ansi_print import ansi_log, raise_nicer_exception
5
from pypy.annotation import model as annmodel
6
from pypy.annotation.pairtype import pair
7
from pypy.annotation.bookkeeper import Bookkeeper, getbookkeeper
8
from pypy.objspace.flow.model import Variable, Constant
9
from pypy.objspace.flow.model import FunctionGraph
10
from pypy.objspace.flow.model import c_last_exception, checkgraph
12
log = py.log.Producer("annrpython")
13
py.log.setconsumer("annrpython", ansi_log)
15
from pypy.tool.error import format_blocked_annotation_error, format_someobject_error, AnnotatorError
19
class RPythonAnnotator(object):
20
"""Block annotator for RPython.
21
See description in doc/translation.txt."""
23
def __init__(self, translator=None, policy=None, bookkeeper=None):
24
import pypy.rpython.ootypesystem.ooregistry # has side effects
25
import pypy.rpython.ootypesystem.bltregistry # has side effects
26
import pypy.rpython.extfuncregistry # has side effects
27
import pypy.rlib.nonconst # has side effects
29
if translator is None:
31
from pypy.translator.translator import TranslationContext
32
translator = TranslationContext()
33
translator.annotator = self
34
self.translator = translator
35
self.pendingblocks = {} # map {block: graph-containing-it}
36
self.bindings = {} # map Variables to SomeValues
37
self.annotated = {} # set of blocks already seen
38
self.added_blocks = None # see processblock() below
39
self.links_followed = {} # set of links that have ever been followed
40
self.notify = {} # {block: {positions-to-reflow-from-when-done}}
41
self.fixed_graphs = {} # set of graphs not to annotate again
42
self.blocked_blocks = {} # set of {blocked_block: graph}
43
# --- the following information is recorded for debugging only ---
44
# --- and only if annotation.model.DEBUG is kept to True
45
self.why_not_annotated = {} # {block: (exc_type, exc_value, traceback)}
46
# records the location of BlockedInference
47
# exceptions that blocked some blocks.
48
self.blocked_graphs = {} # set of graphs that have blocked blocks
49
self.bindingshistory = {}# map Variables to lists of SomeValues
50
self.binding_caused_by = {} # map Variables to position_keys
51
# records the caller position that caused bindings of inputargs
53
self.binding_cause_history = {} # map Variables to lists of positions
54
# history of binding_caused_by, kept in sync with
56
self.reflowcounter = {}
57
self.return_bindings = {} # map return Variables to their graphs
58
# --- end of debugging information ---
61
from pypy.annotation.policy import AnnotatorPolicy
62
self.policy = AnnotatorPolicy()
65
if bookkeeper is None:
66
bookkeeper = Bookkeeper(self)
67
self.bookkeeper = bookkeeper
69
def __getstate__(self):
70
attrs = """translator pendingblocks bindings annotated links_followed
71
notify bookkeeper frozen policy added_blocks""".split()
72
ret = self.__dict__.copy()
73
for key, value in ret.items():
75
assert type(value) is dict, (
76
"%r is not dict. please update %s.__getstate__" %
77
(key, self.__class__.__name__))
81
def _register_returnvar(self, flowgraph):
83
self.return_bindings[flowgraph.getreturnvar()] = flowgraph
85
#___ convenience high-level interface __________________
87
def build_types(self, function, input_arg_types, complete_now=True):
88
"""Recursively build annotations about the specific entry point."""
89
assert isinstance(function, FunctionType), "fix that!"
91
# make input arguments and set their type
92
inputcells = [self.typeannotation(t) for t in input_arg_types]
94
desc = self.bookkeeper.getdesc(function)
95
desc.getcallfamily() # record this implicit call (hint for back-ends)
96
flowgraph = desc.specialize(inputcells)
97
if not isinstance(flowgraph, FunctionGraph):
98
assert isinstance(flowgraph, annmodel.SomeObject)
101
return self.build_graph_types(flowgraph, inputcells, complete_now=complete_now)
103
def get_call_parameters(self, function, args_s, policy):
104
desc = self.bookkeeper.getdesc(function)
105
args = self.bookkeeper.build_args("simple_call", args_s[:])
107
def schedule(graph, inputcells):
108
result.append((graph, inputcells))
109
return annmodel.s_ImpossibleValue
111
prevpolicy = self.policy
113
self.bookkeeper.enter(None)
115
desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
117
self.bookkeeper.leave()
118
self.policy = prevpolicy
119
[(graph, inputcells)] = result
120
return graph, inputcells
122
def annotate_helper(self, function, args_s, policy=None):
124
from pypy.annotation.policy import AnnotatorPolicy
125
policy = AnnotatorPolicy()
126
graph, inputcells = self.get_call_parameters(function, args_s, policy)
127
self.build_graph_types(graph, inputcells, complete_now=False)
128
self.complete_helpers(policy)
131
def annotate_helper_method(self, _class, attr, args_s, policy=None):
132
""" Warning! this method is meant to be used between
133
annotation and rtyping
136
from pypy.annotation.policy import AnnotatorPolicy
137
policy = AnnotatorPolicy()
139
assert attr != '__class__'
140
classdef = self.bookkeeper.getuniqueclassdef(_class)
141
attrdef = classdef.find_attribute(attr)
142
s_result = attrdef.getvalue()
143
classdef.add_source_for_attribute(attr, classdef.classdesc)
145
assert isinstance(s_result, annmodel.SomePBC)
146
olddesc = s_result.descriptions.iterkeys().next()
147
desc = olddesc.bind_self(classdef)
148
args = self.bookkeeper.build_args("simple_call", args_s[:])
149
desc.consider_call_site(self.bookkeeper, desc.getcallfamily(), [desc],
150
args, annmodel.s_ImpossibleValue)
152
def schedule(graph, inputcells):
153
result.append((graph, inputcells))
154
return annmodel.s_ImpossibleValue
156
prevpolicy = self.policy
158
self.bookkeeper.enter(None)
160
desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
162
self.bookkeeper.leave()
163
self.policy = prevpolicy
164
[(graph, inputcells)] = result
165
self.build_graph_types(graph, inputcells, complete_now=False)
166
self.complete_helpers(policy)
169
def complete_helpers(self, policy):
170
saved = self.policy, self.added_blocks
173
self.added_blocks = {}
175
# invoke annotation simplifications for the new blocks
176
self.simplify(block_subset=self.added_blocks)
178
self.policy, self.added_blocks = saved
180
def build_graph_types(self, flowgraph, inputcells, complete_now=True):
181
checkgraph(flowgraph)
183
nbarg = len(flowgraph.getargs())
184
if len(inputcells) != nbarg:
185
raise TypeError("%s expects %d args, got %d" %(
186
flowgraph, nbarg, len(inputcells)))
188
# register the entry point
189
self.addpendinggraph(flowgraph, inputcells)
190
# recursively proceed until no more pending block is left
193
return self.binding(flowgraph.getreturnvar(), None)
195
def gettype(self, variable):
196
"""Return the known type of a control flow graph variable,
197
defaulting to 'object'."""
198
if isinstance(variable, Constant):
199
return type(variable.value)
200
elif isinstance(variable, Variable):
201
cell = self.bindings.get(variable)
203
return cell.knowntype
207
raise TypeError, ("Variable or Constant instance expected, "
208
"got %r" % (variable,))
210
def getuserclassdefinitions(self):
211
"""Return a list of ClassDefs."""
212
return self.bookkeeper.classdefs
214
#___ medium-level interface ____________________________
216
def addpendinggraph(self, flowgraph, inputcells):
217
self._register_returnvar(flowgraph)
218
self.addpendingblock(flowgraph, flowgraph.startblock, inputcells)
220
def addpendingblock(self, graph, block, cells, called_from_graph=None):
221
"""Register an entry point into block with the given input cells."""
222
if graph in self.fixed_graphs:
223
# special case for annotating/rtyping in several phases: calling
224
# a graph that has already been rtyped. Safety-check the new
225
# annotations that are passed in, and don't annotate the old
226
# graph -- it's already low-level operations!
227
for a, s_newarg in zip(graph.getargs(), cells):
228
s_oldarg = self.binding(a)
229
assert s_oldarg.contains(s_newarg)
231
assert not self.frozen
233
assert isinstance(a, annmodel.SomeObject)
234
if block not in self.annotated:
235
self.bindinputargs(graph, block, cells, called_from_graph)
237
self.mergeinputargs(graph, block, cells, called_from_graph)
238
if not self.annotated[block]:
239
self.pendingblocks[block] = graph
242
"""Process pending blocks until none is left."""
244
while self.pendingblocks:
245
block, graph = self.pendingblocks.popitem()
247
self.flowin_block = block # we need to keep track of block
248
self.processblock(graph, block)
249
self.policy.no_more_blocks_to_annotate(self)
250
if not self.pendingblocks:
252
# make sure that the return variables of all graphs is annotated
253
if self.added_blocks is not None:
254
newgraphs = [self.annotated[block] for block in self.added_blocks]
255
newgraphs = dict.fromkeys(newgraphs)
256
got_blocked_blocks = False in newgraphs
258
newgraphs = self.translator.graphs #all of them
259
got_blocked_blocks = False in self.annotated.values()
260
if got_blocked_blocks:
261
for graph in self.blocked_graphs.values():
262
self.blocked_graphs[graph] = True
264
blocked_blocks = [block for block, done in self.annotated.items()
266
assert len(blocked_blocks) == len(self.blocked_blocks)
268
text = format_blocked_annotation_error(self, self.blocked_blocks)
270
raise AnnotatorError(text)
271
for graph in newgraphs:
272
v = graph.getreturnvar()
273
if v not in self.bindings:
274
self.setbinding(v, annmodel.s_ImpossibleValue)
275
# policy-dependent computation
276
self.bookkeeper.compute_at_fixpoint()
278
def binding(self, arg, default=FAIL):
279
"Gives the SomeValue corresponding to the given Variable or Constant."
280
if isinstance(arg, Variable):
282
return self.bindings[arg]
284
if default is not FAIL:
288
elif isinstance(arg, Constant):
289
#if arg.value is undefined_value: # undefined local variables
290
# return annmodel.s_ImpossibleValue
291
return self.bookkeeper.immutableconstant(arg)
293
raise TypeError, 'Variable or Constant expected, got %r' % (arg,)
295
def typeannotation(self, t):
296
if isinstance(t, annmodel.SomeObject):
299
return self.bookkeeper.valueoftype(t)
301
def ondegenerated(self, what, s_value, where=None, called_from_graph=None):
302
if self.policy.allow_someobjects:
304
# is the function itself tagged with allow_someobjects?
305
position_key = where or getattr(self.bookkeeper, 'position_key', None)
306
if position_key is not None:
307
graph, block, i = position_key
309
if graph.func.allow_someobjects:
311
except AttributeError:
314
graph = position_key[0]
315
msgstr = format_someobject_error(self, position_key, what, s_value,
317
self.bindings.get(what, "(none)"))
319
raise AnnotatorError(msgstr)
321
def setbinding(self, arg, s_value, called_from_graph=None, where=None):
322
if arg in self.bindings:
323
assert s_value.contains(self.bindings[arg])
324
# for debugging purposes, record the history of bindings that
325
# have been given to this variable
327
history = self.bindingshistory.setdefault(arg, [])
328
history.append(self.bindings[arg])
329
cause_history = self.binding_cause_history.setdefault(arg, [])
330
cause_history.append(self.binding_caused_by[arg])
332
degenerated = annmodel.isdegenerated(s_value)
335
self.ondegenerated(arg, s_value, where=where,
336
called_from_graph=called_from_graph)
338
self.bindings[arg] = s_value
340
if arg in self.return_bindings:
341
log.event("%s -> %s" %
342
(self.whereami((self.return_bindings[arg], None, None)),
345
if arg in self.return_bindings and degenerated:
346
self.warning("result degenerated to SomeObject",
347
(self.return_bindings[arg],None, None))
349
self.binding_caused_by[arg] = called_from_graph
351
def transfer_binding(self, v_target, v_source):
352
assert v_source in self.bindings
353
self.bindings[v_target] = self.bindings[v_source]
355
self.binding_caused_by[v_target] = None
357
def warning(self, msg, pos=None):
360
pos = self.bookkeeper.position_key
361
except AttributeError:
364
pos = self.whereami(pos)
366
log.WARNING("%s/ %s" % (pos, msg))
369
#___ interface for annotator.bookkeeper _______
371
def recursivecall(self, graph, whence, inputcells): # whence = position_key|callback taking the annotator, graph
372
if isinstance(whence, tuple):
373
parent_graph, parent_block, parent_index = position_key = whence
374
tag = parent_block, parent_index
375
self.translator.update_call_graph(parent_graph, graph, tag)
378
self._register_returnvar(graph)
379
# self.notify[graph.returnblock] is a dictionary of call
380
# points to this func which triggers a reflow whenever the
381
# return block of this graph has been analysed.
382
callpositions = self.notify.setdefault(graph.returnblock, {})
383
if whence is not None:
389
callpositions[callback] = True
391
# generalize the function's input arguments
392
self.addpendingblock(graph, graph.startblock, inputcells,
395
# get the (current) return value
396
v = graph.getreturnvar()
398
return self.bindings[v]
400
# the function didn't reach any return statement so far.
401
# (some functions actually never do, they always raise exceptions)
402
return annmodel.s_ImpossibleValue
404
def reflowfromposition(self, position_key):
405
graph, block, index = position_key
406
self.reflowpendingblock(graph, block)
409
#___ simplification (should be moved elsewhere?) _______
412
# now simplify_calls is moved to transform.py.
413
# i kept reverse_binding here for future(?) purposes though. --sanxiyn
415
def reverse_binding(self, known_variables, cell):
416
"""This is a hack."""
417
# In simplify_calls, when we are trying to create the new
418
# SpaceOperation, all we have are SomeValues. But SpaceOperations take
419
# Variables, not SomeValues. Trouble is, we don't always have a
420
# Variable that just happens to be bound to the given SomeValue.
421
# A typical example would be if the tuple of arguments was created
422
# from another basic block or even another function. Well I guess
423
# there is no clean solution, short of making the transformations
424
# more syntactic (e.g. replacing a specific sequence of SpaceOperations
425
# with another one). This is a real hack because we have to use
426
# the identity of 'cell'.
427
if cell.is_constant():
428
return Constant(cell.const)
430
for v in known_variables:
431
if self.bindings[v] is cell:
436
def simplify(self, block_subset=None, extra_passes=None):
437
# Generic simplifications
438
from pypy.translator import transform
439
transform.transform_graph(self, block_subset=block_subset,
440
extra_passes=extra_passes)
441
from pypy.translator import simplify
442
if block_subset is None:
443
graphs = self.translator.graphs
446
for block in block_subset:
447
graph = self.annotated.get(block)
451
simplify.eliminate_empty_blocks(graph)
454
#___ flowing annotations in blocks _____________________
456
def processblock(self, graph, block):
457
# Important: this is not called recursively.
458
# self.flowin() can only issue calls to self.addpendingblock().
459
# The analysis of a block can be in three states:
460
# * block not in self.annotated:
461
# never seen the block.
462
# * self.annotated[block] == False:
463
# the input variables of the block are in self.bindings but we
464
# still have to consider all the operations in the block.
465
# * self.annotated[block] == graph-containing-block:
466
# analysis done (at least until we find we must generalize the
469
#print '* processblock', block, cells
471
self.reflowcounter.setdefault(block, 0)
472
self.reflowcounter[block] += 1
473
self.annotated[block] = graph
474
if block in self.blocked_blocks:
475
del self.blocked_blocks[block]
477
self.flowin(graph, block)
478
except BlockedInference, e:
479
self.annotated[block] = False # failed, hopefully temporarily
480
self.blocked_blocks[block] = graph
482
# hack for debug tools only
483
if not hasattr(e, '__annotator_block'):
484
setattr(e, '__annotator_block', block)
487
# The dict 'added_blocks' is used by rpython.annlowlevel to
488
# detect which are the new blocks that annotating an additional
489
# small helper creates.
490
if self.added_blocks is not None:
491
self.added_blocks[block] = True
493
def reflowpendingblock(self, graph, block):
494
assert not self.frozen
495
assert graph not in self.fixed_graphs
496
self.pendingblocks[block] = graph
497
assert block in self.annotated
498
self.annotated[block] = False # must re-flow
499
self.blocked_blocks[block] = graph
501
def bindinputargs(self, graph, block, inputcells, called_from_graph=None):
502
# Create the initial bindings for the input args of a block.
503
assert len(block.inputargs) == len(inputcells)
504
where = (graph, block, None)
505
for a, cell in zip(block.inputargs, inputcells):
506
self.setbinding(a, cell, called_from_graph, where=where)
507
self.annotated[block] = False # must flowin.
508
self.blocked_blocks[block] = graph
510
def mergeinputargs(self, graph, block, inputcells, called_from_graph=None):
511
# Merge the new 'cells' with each of the block's existing input
513
oldcells = [self.binding(a) for a in block.inputargs]
514
unions = [annmodel.unionof(c1,c2) for c1, c2 in zip(oldcells,inputcells)]
515
# if the merged cells changed, we must redo the analysis
516
if unions != oldcells:
517
self.bindinputargs(graph, block, unions, called_from_graph)
519
def whereami(self, position_key):
520
graph, block, i = position_key
529
return repr(graph) + blk + opid
531
def flowin(self, graph, block):
532
#print 'Flowing', block, [self.binding(a) for a in block.inputargs]
534
for i in range(len(block.operations)):
536
self.bookkeeper.enter((graph, block, i))
537
self.consider_op(block.operations[i])
539
self.bookkeeper.leave()
541
except BlockedInference, e:
544
self.why_not_annotated[block] = sys.exc_info()
546
if (e.op is block.operations[-1] and
547
block.exitswitch == c_last_exception):
548
# this is the case where the last operation of the block will
549
# always raise an exception which is immediately caught by
550
# an exception handler. We then only follow the exceptional
552
exits = [link for link in block.exits
553
if link.exitcase is not None]
555
elif e.op.opname in ('simple_call', 'call_args', 'next'):
556
# XXX warning, keep the name of the call operations in sync
557
# with the flow object space. These are the operations for
558
# which it is fine to always raise an exception. We then
559
# swallow the BlockedInference and that's it.
560
# About 'next': see test_annotate_iter_empty_container().
564
# other cases are problematic (but will hopefully be solved
565
# later by reflowing). Throw the BlockedInference up to
569
except annmodel.HarmlesslyBlocked:
573
# dead code removal: don't follow all exits if the exitswitch
576
if isinstance(block.exitswitch, Variable):
577
s_exitswitch = self.bindings[block.exitswitch]
578
if s_exitswitch.is_constant():
579
exits = [link for link in exits
580
if link.exitcase == s_exitswitch.const]
582
# mapping (exitcase, variable) -> s_annotation
583
# that can be attached to booleans, exitswitches
584
knowntypedata = getattr(self.bindings.get(block.exitswitch),
587
# filter out those exceptions which cannot
588
# occour for this specific, typed operation.
589
if block.exitswitch == c_last_exception:
590
op = block.operations[-1]
591
if op.opname in annmodel.BINARY_OPERATIONS:
592
arg1 = self.binding(op.args[0])
593
arg2 = self.binding(op.args[1])
594
binop = getattr(pair(arg1, arg2), op.opname, None)
595
can_only_throw = annmodel.read_can_only_throw(binop, arg1, arg2)
596
elif op.opname in annmodel.UNARY_OPERATIONS:
597
arg1 = self.binding(op.args[0])
598
unop = getattr(arg1, op.opname, None)
599
can_only_throw = annmodel.read_can_only_throw(unop, arg1)
601
can_only_throw = None
603
if can_only_throw is not None:
604
candidates = can_only_throw
605
candidate_exits = exits
607
for link in candidate_exits:
612
covered = [c for c in candidates if issubclass(c, case)]
615
candidates = [c for c in candidates if c not in covered]
619
in_except_block = False
621
last_exception_var = link.last_exception # may be None for non-exception link
622
last_exc_value_var = link.last_exc_value # may be None for non-exception link
624
if isinstance(link.exitcase, (types.ClassType, type)) \
625
and issubclass(link.exitcase, Exception):
626
assert last_exception_var and last_exc_value_var
627
last_exc_value_object = self.bookkeeper.valueoftype(link.exitcase)
628
last_exception_object = annmodel.SomeObject()
629
last_exception_object.knowntype = type
630
if isinstance(last_exception_var, Constant):
631
last_exception_object.const = last_exception_var.value
632
last_exception_object.is_type_of = [last_exc_value_var]
634
if isinstance(last_exception_var, Variable):
635
self.setbinding(last_exception_var, last_exception_object)
636
if isinstance(last_exc_value_var, Variable):
637
self.setbinding(last_exc_value_var, last_exc_value_object)
639
last_exception_object = annmodel.SomeObject()
640
last_exception_object.knowntype = type
641
if isinstance(last_exception_var, Constant):
642
last_exception_object.const = last_exception_var.value
643
#if link.exitcase is Exception:
644
# last_exc_value_object = annmodel.SomeObject()
646
last_exc_value_vars = []
647
in_except_block = True
652
for a,v in zip(link.args,link.target.inputargs):
653
renaming.setdefault(a, []).append(v)
654
for a,v in zip(link.args,link.target.inputargs):
655
if a == last_exception_var:
656
assert in_except_block
657
cells.append(last_exception_object)
658
elif a == last_exc_value_var:
659
assert in_except_block
660
cells.append(last_exc_value_object)
661
last_exc_value_vars.append(v)
663
cell = self.binding(a)
664
if (link.exitcase, a) in knowntypedata:
665
knownvarvalue = knowntypedata[(link.exitcase, a)]
666
cell = pair(cell, knownvarvalue).improve()
667
# ignore links that try to pass impossible values
668
if cell == annmodel.s_ImpossibleValue:
671
if hasattr(cell,'is_type_of'):
672
renamed_is_type_of = []
673
for v in cell.is_type_of:
674
new_vs = renaming.get(v,[])
675
renamed_is_type_of += new_vs
676
newcell = annmodel.SomeObject()
677
if cell.knowntype == type:
678
newcell.knowntype = type
679
if cell.is_constant():
680
newcell.const = cell.const
682
cell.is_type_of = renamed_is_type_of
684
if hasattr(cell, 'knowntypedata'):
685
renamed_knowntypedata = {}
686
for (value, v), s in cell.knowntypedata.items():
687
new_vs = renaming.get(v, [])
689
renamed_knowntypedata[value, new_v] = s
690
assert isinstance(cell, annmodel.SomeBool)
691
newcell = annmodel.SomeBool()
692
if cell.is_constant():
693
newcell.const = cell.const
695
cell.knowntypedata = renamed_knowntypedata
703
last_exception_object.is_type_of = last_exc_value_vars
705
self.links_followed[link] = True
706
self.addpendingblock(graph, link.target, cells)
708
if block in self.notify:
709
# reflow from certain positions when this block is done
710
for callback in self.notify[block]:
711
if isinstance(callback, tuple):
712
self.reflowfromposition(callback) # callback is a position
717
#___ creating the annotations based on operations ______
719
def consider_op(self, op):
720
argcells = [self.binding(a) for a in op.args]
721
consider_meth = getattr(self,'consider_op_'+op.opname,
723
if not consider_meth:
724
raise Exception,"unknown op: %r" % op
726
# let's be careful about avoiding propagated SomeImpossibleValues
727
# to enter an op; the latter can result in violations of the
728
# more general results invariant: e.g. if SomeImpossibleValue enters is_
729
# is_(SomeImpossibleValue, None) -> SomeBool
730
# is_(SomeInstance(not None), None) -> SomeBool(const=False) ...
731
# boom -- in the assert of setbinding()
733
if isinstance(arg, annmodel.SomeImpossibleValue):
734
raise BlockedInference(self, op)
736
resultcell = consider_meth(*argcells)
738
graph = self.bookkeeper.position_key[0]
739
raise_nicer_exception(op, str(graph))
740
if resultcell is None:
741
resultcell = self.noreturnvalue(op)
742
elif resultcell == annmodel.s_ImpossibleValue:
743
raise BlockedInference(self, op) # the operation cannot succeed
744
assert isinstance(resultcell, annmodel.SomeObject)
745
assert isinstance(op.result, Variable)
746
self.setbinding(op.result, resultcell) # bind resultcell to op.result
748
def noreturnvalue(self, op):
749
return annmodel.s_ImpossibleValue # no return value (hook method)
751
# XXX "contains" clash with SomeObject method
752
def consider_op_contains(self, seq, elem):
753
self.bookkeeper.count("contains", seq)
754
return seq.op_contains(elem)
756
def consider_op_newtuple(self, *args):
757
return annmodel.SomeTuple(items = args)
759
def consider_op_newlist(self, *args):
760
return self.bookkeeper.newlist(*args)
762
def consider_op_newdict(self):
763
return self.bookkeeper.newdict()
765
def consider_op_newslice(self, start, stop, step):
766
self.bookkeeper.count('newslice', start, stop, step)
767
return annmodel.SomeSlice(start, stop, step)
770
def _registeroperations(cls, model):
771
# All unary operations
773
for opname in model.UNARY_OPERATIONS:
774
fnname = 'consider_op_' + opname
776
def consider_op_%s(self, arg, *args):
778
""" % (opname, opname) in globals(), d
779
setattr(cls, fnname, d[fnname])
780
# All binary operations
781
for opname in model.BINARY_OPERATIONS:
782
fnname = 'consider_op_' + opname
784
def consider_op_%s(self, arg1, arg2, *args):
785
return pair(arg1,arg2).%s(*args)
786
""" % (opname, opname) in globals(), d
787
setattr(cls, fnname, d[fnname])
788
_registeroperations = classmethod(_registeroperations)
790
# register simple operations handling
791
RPythonAnnotator._registeroperations(annmodel)
794
class CannotSimplify(Exception):
798
class BlockedInference(Exception):
799
"""This exception signals the type inference engine that the situation
800
is currently blocked, and that it should try to progress elsewhere."""
802
def __init__(self, annotator, op):
803
self.annotator = annotator
805
self.break_at = annotator.bookkeeper.position_key
806
except AttributeError:
811
if not self.break_at:
814
break_at = self.annotator.whereami(self.break_at)
815
return "<BlockedInference break_at %s [%s]>" %(break_at, self.op)