Commit 185a8f39 authored by Josh Tobin's avatar Josh Tobin

posonly args: bugfixes & address PR comments

parent b3cfe42f
......@@ -3929,7 +3929,7 @@ class DefNodeWrapper(FuncDefNode):
if arg.pos_only:
if i == last_required_posonly_arg:
code.put_goto(argtuple_error_label)
if i == last_required_arg:
elif i == last_required_arg:
code.putln('break;')
continue
if arg.default:
......@@ -4014,12 +4014,17 @@ class DefNodeWrapper(FuncDefNode):
pos_arg_count = "used_pos_args"
else:
pos_arg_count = "kwd_pos_args"
if num_pos_only_args > 0 and num_pos_only_args < len(all_args):
values_array = 'values + %d' % (num_pos_only_args)
else:
values_array = 'values'
code.globalstate.use_utility_code(
UtilityCode.load_cached("ParseKeywords", "FunctionArguments.c"))
code.putln('if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, values, %s, "%s") < 0)) %s' % (
code.putln('if (unlikely(__Pyx_ParseOptionalKeywords(%s, %s, %s, %s, %s, "%s") < 0)) %s' % (
Naming.kwds_cname,
Naming.pykwdlist_cname,
self.starstar_arg and self.starstar_arg.entry.cname or '0',
values_array,
pos_arg_count,
self.name,
code.error_goto(self.pos)))
......@@ -4028,12 +4033,19 @@ class DefNodeWrapper(FuncDefNode):
def generate_optional_kwonly_args_unpacking_code(self, all_args, code):
optional_args = []
first_optional_arg = -1
num_posonly_args = 0
for i, arg in enumerate(all_args):
if arg.pos_only:
num_posonly_args += 1
if not arg.kw_only or not arg.default:
continue
if not optional_args:
first_optional_arg = i
optional_args.append(arg.name)
if num_posonly_args > 0:
posonly_correction = '-%d' % num_posonly_args
else:
posonly_correction = ''
if optional_args:
if len(optional_args) > 1:
# if we receive more than the named kwargs, we either have **kwargs
......@@ -4049,8 +4061,8 @@ class DefNodeWrapper(FuncDefNode):
else:
code.putln('if (kw_args == 1) {')
code.putln('const Py_ssize_t index = %d;' % first_optional_arg)
code.putln('PyObject* value = __Pyx_PyDict_GetItemStr(%s, *%s[index]);' % (
Naming.kwds_cname, Naming.pykwdlist_cname))
code.putln('PyObject* value = __Pyx_PyDict_GetItemStr(%s, *%s[index%s]);' % (
Naming.kwds_cname, Naming.pykwdlist_cname, posonly_correction))
code.putln('if (value) { values[index] = value; kw_args--; }')
if len(optional_args) > 1:
code.putln('}')
......
# mode: compile
# tag: posonly
# TODO: remove posonly tag before merge (and maybe remove this test,
# since it seems covered by the runs/ test)
def test(x, y, z=42, /, w=43):
pass
def test2(x, y, /):
pass
def test3(x, /, z):
pass
def test4(x, /, z, *, w):
pass
# mode: error
# tag: posonly
def f(a, b = 5, /, c):
pass
def f(a = 5, b, /, c):
pass
def f(a = 5, b, /):
pass
def f(a, /, a):
pass
def f(a, /, *, a):
pass
#def f(a, b/2, c): #D
# pass
#def f(*args, /): #D
# pass
#def f(*args, a, /):
# pass
#def f(**kwargs, /):
# pass
#def f(/, a = 1): # D
# pass
#def f(/, a):
# pass
#def f(/):
# pass
#def f(*, a, /):
# pass
#def f(*, /, a):
# pass
#def f(a, /, c, /):
# pass
#def f(a, /, c, /, d):
# pass
#def f(a, /, c, /, d, *, e):
# pass
#def f(a, *, c, /, d, e):
# pass
def test_invalid_syntax_lambda(self):
lambda a, b = 5, /, c: None
lambda a = 5, b, /, c: None
lambda a = 5, b, /: None
lambda a, /, a: None
lambda a, /, *, a: None
# lambda *args, /: None
# lambda *args, a, /: None
# lambda **kwargs, /: None
# lambda /, a = 1: None
# lambda /, a: None
# lambda /: None
# lambda *, a, /: None
# lambda *, /, a: None
async def f(a, b = 5, /, c):
pass
#def test_multiple_seps(a,/,b,/):
# pass
_ERRORS = u"""
4:19: Non-default argument following default argument
7:13: Non-default argument following default argument
7:19: Non-default argument following default argument
10:13: Non-default argument following default argument
13:6: Previous declaration is here
13:12: 'a' redeclared
16:6: Previous declaration is here
16:15: 'a' redeclared
59:24: Non-default argument following default argument
60:18: Non-default argument following default argument
60:24: Non-default argument following default argument
61:18: Non-default argument following default argument
62:11: Previous declaration is here
62:17: 'a' redeclared
63:11: Previous declaration is here
63:20: 'a' redeclared
73:25: Non-default argument following default argument
"""
# mode: error
# tag: posonly
def f(a, b/2, c):
pass
_ERRORS = u"""
4:11: Syntax error in Python function argument list
"""
# mode: error
# tag: posonly
def f(*args, /):
pass
def f(*args, a, /):
pass
_ERRORS = u"""
4:13: Expected ')', found '/'
"""
# mode: error
# tag: posonly
def f(/, a = 1):
pass
_ERRORS = u"""
4:6: Got zero positional-only arguments despite presence of positional-only specifier '/'
"""
# mode: error
# tag: posonly
def test_multiple_seps(a,/,b,/):
pass
_ERRORS = u"""
4:29: Expected ')', found '/'
"""
This diff is collapsed.
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