Commit 406674e1 authored by Stefan Behnel's avatar Stefan Behnel

generic way to wrap an ExprNode in a NoneCheckNode

parent d1b5807f
......@@ -636,10 +636,22 @@ class ExprNode(Node):
# a constant, local var, C global var, struct member
# reference, or temporary.
return self.result_in_temp()
def may_be_none(self):
return self.type.is_pyobject
def as_cython_attribute(self):
return None
def as_none_safe_node(self, error, message):
# Wraps the node in a NoneCheckNode if it is not known to be
# not-None (e.g. because it is a Python literal).
if self.may_be_none():
return NoneCheckNode(self, error, message)
else:
return self
class AtomicExprNode(ExprNode):
# Abstract base class for expression nodes which have
# no sub-expressions.
......@@ -660,7 +672,10 @@ class PyConstNode(AtomicExprNode):
def is_simple(self):
return 1
def may_be_none(self):
return False
def analyse_types(self, env):
pass
......@@ -682,7 +697,11 @@ class NoneNode(PyConstNode):
def compile_time_value(self, denv):
return None
def may_be_none(self):
return True
class EllipsisNode(PyConstNode):
# '...' in a subscript list.
......@@ -704,7 +723,10 @@ class ConstNode(AtomicExprNode):
def is_simple(self):
return 1
def may_be_none(self):
return False
def analyse_types(self, env):
pass # Types are held in class variables
......@@ -1012,6 +1034,9 @@ class LongNode(AtomicExprNode):
def analyse_types(self, env):
self.is_temp = 1
def may_be_none(self):
return False
gil_message = "Constructing Python long int"
def generate_result_code(self, code):
......@@ -1039,6 +1064,9 @@ class ImagNode(AtomicExprNode):
def analyse_types(self, env):
self.type.create_declaration_utility_code(env)
def may_be_none(self):
return False
def coerce_to(self, dst_type, env):
if self.type is dst_type:
return self
......@@ -1098,7 +1126,10 @@ class NewExprNode(AtomicExprNode):
def analyse_types(self, env):
if self.type is None:
self.infer_type(env)
def may_be_none(self):
return False
def generate_result_code(self, code):
pass
......@@ -2958,6 +2989,9 @@ class AsTupleNode(ExprNode):
self.type = tuple_type
self.is_temp = 1
def may_be_none(self):
return False
nogil_check = Node.gil_error
gil_message = "Constructing Python tuple"
......@@ -3434,6 +3468,9 @@ class SequenceNode(ExprNode):
self.type = py_object_type
self.is_temp = 1
def may_be_none(self):
return False
def analyse_target_types(self, env):
self.iterator = PyTempNode(self.pos, env)
self.unpacked_items = []
......@@ -3817,6 +3854,9 @@ class ComprehensionNode(ExprNode):
self.type = self.target.type
self.loop.analyse_expressions(env)
def may_be_none(self):
return False
def calculate_result_code(self):
return self.target.result()
......@@ -3897,6 +3937,9 @@ class SetNode(ExprNode):
self.type = set_type
self.is_temp = 1
def may_be_none(self):
return False
def calculate_constant_result(self):
self.constant_result = set([
arg.constant_result for arg in self.args])
......@@ -3964,6 +4007,9 @@ class DictNode(ExprNode):
item.analyse_types(env)
self.obj_conversion_errors = held_errors()
release_errors(ignore=True)
def may_be_none(self):
return False
def coerce_to(self, dst_type, env):
if dst_type.is_pyobject:
......@@ -4094,6 +4140,9 @@ class ClassNode(ExprNode):
self.is_temp = 1
env.use_utility_code(create_class_utility_code);
def may_be_none(self):
return False
gil_message = "Constructing Python class"
def generate_result_code(self, code):
......@@ -4129,6 +4178,9 @@ class UnboundMethodNode(ExprNode):
def analyse_types(self, env):
self.function.analyse_types(env)
def may_be_none(self):
return False
gil_message = "Constructing an unbound method"
def generate_result_code(self, code):
......@@ -4154,6 +4206,9 @@ class PyCFunctionNode(AtomicExprNode):
def analyse_types(self, env):
pass
def may_be_none(self):
return False
gil_message = "Constructing Python function"
......@@ -4675,7 +4730,10 @@ class TypeofNode(ExprNode):
self.pos, value=StringEncoding.EncodedString(str(self.operand.type)))
self.literal.analyse_types(env)
self.literal = self.literal.coerce_to_pyobject(env)
def may_be_none(self):
return False
def generate_evaluation_code(self, code):
self.literal.generate_evaluation_code(code)
......@@ -5756,8 +5814,8 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self.operand2 = self.operand2.coerce_to(bytes_type, env)
env.use_utility_code(char_in_bytes_utility_code)
if not isinstance(self.operand2, (UnicodeNode, BytesNode)):
self.operand2 = NoneCheckNode(
self.operand2, "PyExc_TypeError",
self.operand2 = self.operand2.as_none_safe_node(
"PyExc_TypeError",
"argument of type 'NoneType' is not iterable")
else:
common_type = py_object_type
......@@ -6087,6 +6145,9 @@ class NoneCheckNode(CoercionNode):
def analyse_types(self, env):
pass
def may_be_none(self):
return False
def result_in_temp(self):
return self.arg.result_in_temp()
......@@ -6129,6 +6190,10 @@ class CoerceToPyTypeNode(CoercionNode):
gil_message = "Converting to Python object"
def may_be_none(self):
# FIXME: is this always safe?
return False
def coerce_to_boolean(self, env):
return self.arg.coerce_to_boolean(env).coerce_to_temp(env)
......@@ -6351,6 +6416,9 @@ class ModuleRefNode(ExprNode):
def analyse_types(self, env):
pass
def may_be_none(self):
return False
def calculate_result_code(self):
return Naming.module_cname
......
......@@ -173,8 +173,7 @@ class IterationTransform(Visitor.VisitorTransform):
return node
unpack_temp_node = UtilNodes.LetRefNode(
ExprNodes.NoneCheckNode(
slice_node, "PyExc_TypeError", "'NoneType' is not iterable"))
slice_node.as_none_safe_node("PyExc_TypeError", "'NoneType' is not iterable"))
slice_base_node = ExprNodes.PythonCapiCallNode(
slice_node.pos, unpack_func, unpack_func_type,
......@@ -1313,8 +1312,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node
arg = pos_args[0]
if arg.type is Builtin.dict_type:
arg = ExprNodes.NoneCheckNode(
arg, "PyExc_TypeError", "'NoneType' is not iterable")
arg = arg.as_none_safe_node("PyExc_TypeError", "'NoneType' is not iterable")
return ExprNodes.PythonCapiCallNode(
node.pos, "PyDict_Copy", self.PyDict_Copy_func_type,
args = [arg],
......@@ -1337,9 +1335,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return node
if not isinstance(list_arg, (ExprNodes.ComprehensionNode,
ExprNodes.ListNode)):
pos_args[0] = ExprNodes.NoneCheckNode(
list_arg, "PyExc_TypeError",
"'NoneType' object is not iterable")
pos_args[0] = list_arg.as_none_safe_node(
"PyExc_TypeError", "'NoneType' object is not iterable")
return ExprNodes.PythonCapiCallNode(
node.pos, "PyList_AsTuple", self.PyList_AsTuple_func_type,
......@@ -1499,9 +1496,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if cfunc_name is None:
return node
if not arg.is_literal:
arg = ExprNodes.NoneCheckNode(
arg, "PyExc_TypeError",
"object of type 'NoneType' has no len()")
arg = arg.as_none_safe_node(
"PyExc_TypeError", "object of type 'NoneType' has no len()")
new_node = ExprNodes.PythonCapiCallNode(
node.pos, cfunc_name, self.PyObject_Size_func_type,
args = [arg],
......@@ -1564,8 +1560,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if not type_arg.type_entry:
# arbitrary variable, needs a None check for safety
type_arg = ExprNodes.NoneCheckNode(
type_arg, "PyExc_TypeError",
type_arg = type_arg.as_none_safe_node(
"PyExc_TypeError",
"object.__new__(X): X is not a type object (NoneType)")
return ExprNodes.PythonCapiCallNode(
......@@ -2126,13 +2122,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
if args and not args[0].is_literal:
self_arg = args[0]
if is_unbound_method:
self_arg = ExprNodes.NoneCheckNode(
self_arg, "PyExc_TypeError",
self_arg = self_arg.as_none_safe_node(
"PyExc_TypeError",
"descriptor '%s' requires a '%s' object but received a 'NoneType'" % (
attr_name, node.function.obj.name))
attr_name, node.function.obj.name))
else:
self_arg = ExprNodes.NoneCheckNode(
self_arg, "PyExc_AttributeError",
self_arg = self_arg.as_none_safe_node(
"PyExc_AttributeError",
"'NoneType' object has no attribute '%s'" % attr_name)
args[0] = self_arg
return ExprNodes.PythonCapiCallNode(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment