Commit 7c016d54 authored by Stefan Behnel's avatar Stefan Behnel

implement 'allow_none_for_extension_args' directive for 'not None' and 'or None' arg anntation

parent 2feda80f
......@@ -630,6 +630,8 @@ class CArgDeclNode(Node):
# base_type CBaseTypeNode
# declarator CDeclaratorNode
# not_none boolean Tagged with 'not None'
# or_none boolean Tagged with 'or None'
# accept_none boolean Resolved boolean for not_none/or_none
# default ExprNode or None
# default_value PyObjectConst constant for default value
# is_self_arg boolean Is the "self" arg of an extension type method
......@@ -1658,7 +1660,7 @@ class CFuncDefNode(FuncDefNode):
'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
arg_code,
typeptr_cname,
not arg.not_none,
arg.accept_none,
arg.name,
type.is_builtin_type,
code.error_goto(arg.pos)))
......@@ -1849,6 +1851,7 @@ class DefNode(FuncDefNode):
def analyse_argument_types(self, env):
directive_locals = self.directive_locals = env.directives['locals']
allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
for arg in self.args:
if hasattr(arg, 'name'):
type = arg.type
......@@ -1877,9 +1880,19 @@ class DefNode(FuncDefNode):
arg.needs_conversion = 0
arg.needs_type_test = 0
arg.is_generic = 1
if arg.not_none and not arg.type.is_extension_type:
error(self.pos,
"Only extension type arguments can have 'not None'")
if arg.type.is_extension_type:
if arg.or_none:
arg.accept_none = True
elif arg.not_none:
arg.accept_none = False
else:
# default depends on compiler directive
arg.accept_none = allow_none_for_extension_args
else:
if arg.not_none:
error(self.pos, "Only extension type arguments can have 'not None'")
if arg.or_none:
error(self.pos, "Only extension type arguments can have 'or None'")
def analyse_signature(self, env):
any_type_tests_needed = 0
......@@ -2650,7 +2663,7 @@ class DefNode(FuncDefNode):
'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
arg_code,
typeptr_cname,
not arg.not_none,
arg.accept_none,
arg.name,
arg.type.is_builtin_type,
code.error_goto(arg.pos)))
......
......@@ -58,6 +58,7 @@ directive_defaults = {
'cdivision': False, # was True before 0.12
'cdivision_warnings': False,
'always_allow_keywords': False,
'allow_none_for_extension_args': True,
'wraparound' : True,
'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "",
......
......@@ -2081,7 +2081,7 @@ def p_optional_ellipsis(s):
def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0):
pos = s.position()
not_none = 0
not_none = or_none = 0
default = None
if s.in_python_file:
# empty type declaration
......@@ -2093,15 +2093,17 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0)
else:
base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty)
declarator = p_c_declarator(s, ctx, nonempty = nonempty)
if s.sy == 'not' and not s.in_python_file:
if s.sy in ('not', 'or') and not s.in_python_file:
kind = s.sy
s.next()
if s.sy == 'IDENT' and s.systring == 'None':
s.next()
else:
s.error("Expected 'None'")
if not in_pyfunc:
error(pos, "'not None' only allowed in Python functions")
not_none = 1
error(pos, "'%s None' only allowed in Python functions" % kind)
or_none = kind == 'or'
not_none = kind == 'not'
if s.sy == '=':
s.next()
if 'pxd' in s.level:
......@@ -2115,6 +2117,7 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0)
base_type = base_type,
declarator = declarator,
not_none = not_none,
or_none = or_none,
default = default,
kw_only = kw_only)
......
......@@ -1638,7 +1638,12 @@ class CFuncTypeArg(object):
# cname string
# type PyrexType
# pos source file position
# FIXME: is this the right setup? should None be allowed here?
not_none = False
or_none = False
accept_none = True
def __init__(self, name, type, pos, cname=None):
self.name = name
if cname is not None:
......@@ -1647,7 +1652,6 @@ class CFuncTypeArg(object):
self.cname = Naming.var_prefix + name
self.type = type
self.pos = pos
self.not_none = False
self.needs_type_test = False # TODO: should these defaults be set in analyse_types()?
def __repr__(self):
......
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