# 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
'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)))
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
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
'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)))
'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' : "",
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
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:
base_type = base_type,
declarator = declarator,
not_none = not_none,
+ or_none = or_none,
default = default,
kw_only = kw_only)
# 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:
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):