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