from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
- from TypeInference import MarkAssignments
+ from TypeInference import MarkAssignments, MarkOverflowingArithmatic
from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck
from AnalysedTreeTransforms import AutoTestDictTransform
from AutoDocTransforms import EmbedSignature
EmbedSignature(self),
EarlyReplaceBuiltinCalls(self),
MarkAssignments(self),
+ MarkOverflowingArithmatic(self),
TransformBuiltinMethods(self),
IntroduceBufferAuxiliaryVars(self),
_check_c_declarations,
for phase in pipeline:
if phase is not None:
if DebugFlags.debug_verbose_pipeline:
+ t = time()
print "Entering pipeline phase %r" % phase
data = phase(data)
+ if DebugFlags.debug_verbose_pipeline:
+ print " %.3f seconds" % (time() - t)
except CompileError, err:
# err is set
Errors.report_error(err)
self.visitchildren(node)
return node
+class MarkOverflowingArithmatic(CythonTransform):
+
+ # It may be possible to integrate this with the above for
+ # performance improvements (though likely not worth it).
+
+ might_overflow = False
+
+ def __call__(self, root):
+ self.env_stack = []
+ self.env = root.scope
+ return super(MarkOverflowingArithmatic, self).__call__(root)
+
+ def visit_safe_node(self, node):
+ self.might_overflow, saved = False, self.might_overflow
+ self.visitchildren(node)
+ self.might_overflow = saved
+ return node
+
+ def visit_neutral_node(self, node):
+ self.visitchildren(node)
+ return node
+
+ def visit_dangerous_node(self, node):
+ self.might_overflow, saved = True, self.might_overflow
+ self.visitchildren(node)
+ self.might_overflow = saved
+ return node
+
+ def visit_FuncDefNode(self, node):
+ self.env_stack.append(self.env)
+ self.env = node.local_scope
+ self.visit_safe_node(node)
+ self.env = self.env_stack.pop()
+ return node
+
+ def visit_NameNode(self, node):
+ if self.might_overflow:
+ entry = node.entry or self.env.lookup(node.name)
+ if entry:
+ entry.might_overflow = True
+ return node
+
+ def visit_BinopNode(self, node):
+ if node.operator in '&|^':
+ return self.visit_neutral_node(node)
+ else:
+ return self.visit_dangerous_node(node)
+
+ visit_UnopNode = visit_neutral_node
+
+ visit_UnaryMinusNode = visit_dangerous_node
+
+ visit_Node = visit_safe_node
+
class PyObjectTypeInferer:
"""
entry = ready_to_infer.pop()
types = [expr.infer_type(scope) for expr in entry.assignments]
if types:
- entry.type = spanning_type(types)
+ entry.type = spanning_type(types, entry.might_overflow)
else:
# FIXME: raise a warning?
# print "No assignments", entry.pos, entry
if len(deps) == 1 and deps == set([entry]):
types = [expr.infer_type(scope) for expr in entry.assignments if expr.type_dependencies(scope) == ()]
if types:
- entry.type = spanning_type(types)
+ entry.type = spanning_type(types, entry.might_overflow)
types = [expr.infer_type(scope) for expr in entry.assignments]
- entry.type = spanning_type(types) # might be wider...
+ entry.type = spanning_type(types, entry.might_overflow) # might be wider...
resolve_dependancy(entry)
del dependancies_by_entry[entry]
if ready_to_infer:
return PyrexTypes.c_double_type
return result_type
-def aggressive_spanning_type(types):
+def aggressive_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types)
return result_type
-def safe_spanning_type(types):
+def safe_spanning_type(types, might_overflow):
result_type = reduce(find_spanning_type, types)
if result_type.is_pyobject:
# any specific Python type is always safe to infer
return result_type
# TODO: double complex should be OK as well, but we need
# to make sure everything is supported.
+ elif result_type.is_int and not might_overflow:
+ return result_type
return py_object_type