Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
ca25dfd2
Commit
ca25dfd2
authored
May 11, 2019
by
Josh Tobin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
posonly_optimization: address review feedback
parent
aae70a1c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
67 additions
and
33 deletions
+67
-33
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+46
-25
tests/run/posonly.pyx
tests/run/posonly.pyx
+21
-8
No files found.
Cython/Compiler/Nodes.py
View file @
ca25dfd2
...
@@ -3692,12 +3692,10 @@ class DefNodeWrapper(FuncDefNode):
...
@@ -3692,12 +3692,10 @@ class DefNodeWrapper(FuncDefNode):
code
.
putln
(
'{'
)
code
.
putln
(
'{'
)
all_args
=
tuple
(
positional_args
)
+
tuple
(
kw_only_args
)
all_args
=
tuple
(
positional_args
)
+
tuple
(
kw_only_args
)
non_posonly_args
=
[
arg
for
arg
in
all_args
if
not
arg
.
pos_only
]
non_posonly_args
=
[
arg
for
arg
in
all_args
if
not
arg
.
pos_only
]
do_generate_kw_unpacking
=
bool
(
non_posonly_args
)
or
self
.
starstar_arg
code
.
putln
(
"static PyObject **%s[] = {%s};"
%
(
if
do_generate_kw_unpacking
:
Naming
.
pykwdlist_cname
,
code
.
putln
(
"static PyObject **%s[] = {%s};"
%
(
','
.
join
([
'&%s'
%
code
.
intern_identifier
(
arg
.
name
)
Naming
.
pykwdlist_cname
,
for
arg
in
non_posonly_args
]
+
[
'0'
])))
','
.
join
([
'&%s'
%
code
.
intern_identifier
(
arg
.
name
)
for
arg
in
non_posonly_args
]
+
[
'0'
])))
# Before being converted and assigned to the target variables,
# Before being converted and assigned to the target variables,
# borrowed references to all unpacked argument values are
# borrowed references to all unpacked argument values are
...
@@ -3709,18 +3707,41 @@ class DefNodeWrapper(FuncDefNode):
...
@@ -3709,18 +3707,41 @@ class DefNodeWrapper(FuncDefNode):
# was passed for them.
# was passed for them.
self
.
generate_argument_values_setup_code
(
all_args
,
code
)
self
.
generate_argument_values_setup_code
(
all_args
,
code
)
# If all args are positional-only, we can raise an error
# straight away if we receive a non-empty kw-dict.
# This requires a PyDict_Size call. This call is wasteful
# for functions which do accept kw-args, so we do not generate
# the PyDict_Size call unless all args are positional-only.
accept_kwd_args
=
non_posonly_args
or
self
.
starstar_arg
if
accept_kwd_args
:
kw_unpacking_condition
=
Naming
.
kwds_cname
else
:
kw_unpacking_condition
=
"%s && PyDict_Size(%s) > 0"
%
(
Naming
.
kwds_cname
,
Naming
.
kwds_cname
)
# --- optimised code when we receive keyword arguments
# --- optimised code when we receive keyword arguments
code
.
putln
(
"if (%s(%s)) {"
%
(
code
.
putln
(
"if (%s(%s)) {"
%
(
(
self
.
num_required_kw_args
>
0
)
and
"likely"
or
"unlikely"
,
(
self
.
num_required_kw_args
>
0
)
and
"likely"
or
"unlikely"
,
Naming
.
kwds_cname
))
kw_unpacking_condition
))
if
do_generate_kw_unpacking
:
if
accept_kwd_args
:
self
.
generate_keyword_unpacking_code
(
self
.
generate_keyword_unpacking_code
(
min_positional_args
,
max_positional_args
,
min_positional_args
,
max_positional_args
,
has_fixed_positional_count
,
has_kw_only_args
,
all_args
,
argtuple_error_label
,
code
)
has_fixed_positional_count
,
has_kw_only_args
,
all_args
,
argtuple_error_label
,
code
)
else
:
else
:
code
.
putln
(
"PyErr_Format(PyExc_TypeError,
\
"
%s() takes no keyword arguments
\
"
);"
%
self
.
name
)
# Here we do not accept kw-args but we are passed a non-empty kw-dict.
code
.
putln
(
code
.
error_goto
(
self
.
pos
))
# We call ParseOptionalKeywords which will raise an appropriate error if
# the kw-args dict passed is non-empty.
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"ParseKeywords"
,
"FunctionArguments.c"
))
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'
,
0
,
self
.
name
,
code
.
error_goto
(
self
.
pos
)))
# --- optimised code when we do not receive any keyword arguments
# --- optimised code when we do not receive any keyword arguments
if
(
self
.
num_required_kw_args
and
min_positional_args
>
0
)
or
min_positional_args
==
max_positional_args
:
if
(
self
.
num_required_kw_args
and
min_positional_args
>
0
)
or
min_positional_args
==
max_positional_args
:
...
@@ -3899,25 +3920,27 @@ class DefNodeWrapper(FuncDefNode):
...
@@ -3899,25 +3920,27 @@ class DefNodeWrapper(FuncDefNode):
code
.
putln
(
'switch (pos_args) {'
)
code
.
putln
(
'switch (pos_args) {'
)
if
self
.
star_arg
:
if
self
.
star_arg
:
code
.
putln
(
'default:'
)
code
.
putln
(
'default:'
)
for
i
in
range
(
max_positional_args
-
1
,
-
1
,
-
1
):
for
i
in
range
(
max_positional_args
-
1
,
num_required_posonly_args
-
1
,
-
1
):
code
.
put
(
'case %2d: '
%
(
i
+
1
))
code
.
put
(
'case %2d: '
%
(
i
+
1
))
if
i
+
1
>
num_required_posonly_args
:
code
.
putln
(
"values[%d] = PyTuple_GET_ITEM(%s, %d);"
%
(
i
,
Naming
.
args_cname
,
i
))
code
.
putln
(
'CYTHON_FALLTHROUGH;'
)
if
num_required_posonly_args
>
0
:
code
.
put
(
'case %2d: '
%
num_required_posonly_args
)
for
i
in
range
(
num_required_posonly_args
-
1
,
-
1
,
-
1
):
code
.
putln
(
"values[%d] = PyTuple_GET_ITEM(%s, %d);"
%
(
code
.
putln
(
"values[%d] = PyTuple_GET_ITEM(%s, %d);"
%
(
i
,
Naming
.
args_cname
,
i
))
i
,
Naming
.
args_cname
,
i
))
code
.
putln
(
'CYTHON_FALLTHROUGH;'
)
code
.
putln
(
'break;'
)
elif
i
+
1
==
num_required_posonly_args
:
for
i
in
range
(
num_required_posonly_args
-
2
,
-
1
,
-
1
):
for
j
in
range
(
num_required_posonly_args
-
1
,
-
1
,
-
1
):
code
.
put
(
'case %2d: '
%
(
i
+
1
))
code
.
putln
(
"values[%d] = PyTuple_GET_ITEM(%s, %d);"
%
(
code
.
putln
(
'CYTHON_FALLTHROUGH;'
)
j
,
Naming
.
args_cname
,
j
))
code
.
putln
(
'break;'
)
else
:
code
.
putln
(
'CYTHON_FALLTHROUGH;'
)
code
.
put
(
'case 0: '
)
if
num_required_posonly_args
==
0
:
if
num_required_posonly_args
==
0
:
code
.
putln
(
'
case 0:
break;'
)
code
.
putln
(
'break;'
)
else
:
else
:
# catch-all for not enough pos-only args passed
# catch-all for not enough pos-only args passed
code
.
putln
(
'case 0:'
)
code
.
put_goto
(
argtuple_error_label
)
code
.
put_goto
(
argtuple_error_label
)
if
not
self
.
star_arg
:
if
not
self
.
star_arg
:
code
.
put
(
'default: '
)
# more arguments than allowed
code
.
put
(
'default: '
)
# more arguments than allowed
...
@@ -3943,9 +3966,7 @@ class DefNodeWrapper(FuncDefNode):
...
@@ -3943,9 +3966,7 @@ class DefNodeWrapper(FuncDefNode):
last_required_arg
=
max_positional_args
-
1
last_required_arg
=
max_positional_args
-
1
if
max_positional_args
>
num_posonly_args
:
if
max_positional_args
>
num_posonly_args
:
code
.
putln
(
'switch (pos_args) {'
)
code
.
putln
(
'switch (pos_args) {'
)
for
i
,
arg
in
enumerate
(
all_args
[:
last_required_arg
+
1
]):
for
i
,
arg
in
enumerate
(
all_args
[
num_posonly_args
:
last_required_arg
+
1
],
num_posonly_args
):
if
i
<
num_posonly_args
:
continue
if
max_positional_args
>
num_posonly_args
and
i
<=
max_positional_args
:
if
max_positional_args
>
num_posonly_args
and
i
<=
max_positional_args
:
if
i
!=
num_posonly_args
:
if
i
!=
num_posonly_args
:
code
.
putln
(
'CYTHON_FALLTHROUGH;'
)
code
.
putln
(
'CYTHON_FALLTHROUGH;'
)
...
...
tests/run/posonly.pyx
View file @
ca25dfd2
...
@@ -2,8 +2,6 @@
...
@@ -2,8 +2,6 @@
# mode: run
# mode: run
# tag: posonly
# tag: posonly
# TODO: remove posonly tag before merge
import
cython
import
cython
import
sys
import
sys
import
pickle
import
pickle
...
@@ -126,7 +124,7 @@ def test_use_positional_as_keyword3(a, b, /):
...
@@ -126,7 +124,7 @@ def test_use_positional_as_keyword3(a, b, /):
>>> test_use_positional_as_keyword3(1, 2)
>>> test_use_positional_as_keyword3(1, 2)
>>> test_use_positional_as_keyword3(a=1, b=2)
>>> test_use_positional_as_keyword3(a=1, b=2)
Traceback (most recent call last):
Traceback (most recent call last):
TypeError: test_use_positional_as_keyword3()
takes no keyword arguments
TypeError: test_use_positional_as_keyword3()
got an unexpected keyword argument 'a'
"""
"""
def
test_positional_only_and_arg_invalid_calls
(
a
,
b
,
/
,
c
):
def
test_positional_only_and_arg_invalid_calls
(
a
,
b
,
/
,
c
):
...
@@ -266,7 +264,7 @@ class TestPosonlyMethods(object):
...
@@ -266,7 +264,7 @@ class TestPosonlyMethods(object):
Got type error
Got type error
>>> TestPosonlyMethods().f(1, b=2)
>>> TestPosonlyMethods().f(1, b=2)
Traceback (most recent call last):
Traceback (most recent call last):
TypeError: f()
takes no keyword arguments
TypeError: f()
got an unexpected keyword argument 'b'
"""
"""
def
f
(
self
,
a
,
b
,
/
):
def
f
(
self
,
a
,
b
,
/
):
return
a
,
b
return
a
,
b
...
@@ -367,7 +365,7 @@ def test_serialization1(a, b, /):
...
@@ -367,7 +365,7 @@ def test_serialization1(a, b, /):
(1, 2)
(1, 2)
>>> unpickled_posonly(a=1, b=2)
>>> unpickled_posonly(a=1, b=2)
Traceback (most recent call last):
Traceback (most recent call last):
TypeError: test_serialization1()
takes no keyword arguments
TypeError: test_serialization1()
got an unexpected keyword argument 'a'
"""
"""
return
(
a
,
b
)
return
(
a
,
b
)
...
@@ -510,7 +508,8 @@ def f_call_posonly_kwarg(a,/,**kw):
...
@@ -510,7 +508,8 @@ def f_call_posonly_kwarg(a,/,**kw):
"""
"""
>>> f_call_posonly_kwarg(1)
>>> f_call_posonly_kwarg(1)
(1, {})
(1, {})
>>> f_call_posonly_kwarg(1, b=2, c=3, d=4)==(1, {'b': 2, 'c': 3, 'd': 4})
>>> all_args = f_call_posonly_kwarg(1, b=2, c=3, d=4)
>>> all_args == (1, {'b': 2, 'c': 3, 'd': 4}) or all_args
True
True
"""
"""
return
(
a
,
kw
)
return
(
a
,
kw
)
...
@@ -521,9 +520,23 @@ def f_call_posonly_stararg_kwarg(a,/,*args,**kw):
...
@@ -521,9 +520,23 @@ def f_call_posonly_stararg_kwarg(a,/,*args,**kw):
(1, (), {})
(1, (), {})
>>> f_call_posonly_stararg_kwarg(1, 2)
>>> f_call_posonly_stararg_kwarg(1, 2)
(1, (2,), {})
(1, (2,), {})
>>> f_call_posonly_stararg_kwarg(1, b=3, c=4)==(1, (), {'b': 3, 'c': 4})
>>> all_args = f_call_posonly_stararg_kwarg(1, b=3, c=4)
>>> all_args == (1, (), {'b': 3, 'c': 4}) or all_args
True
True
>>> f_call_posonly_stararg_kwarg(1, 2, b=3, c=4)==(1, (2,), {'b': 3, 'c': 4})
>>> all_args = f_call_posonly_stararg_kwarg(1, 2, b=3, c=4)
>>> all_args == (1, (2,), {'b': 3, 'c': 4}) or all_args
True
True
"""
"""
return
(
a
,
args
,
kw
)
return
(
a
,
args
,
kw
)
def
test_empty_kwargs
(
a
,
b
,
/
):
"""
>>> test_empty_kwargs(1, 2)
(1, 2)
>>> test_empty_kwargs(1, 2, **{})
(1, 2)
>>> test_empty_kwargs(1, 2, **{'c': 3})
Traceback (most recent call last):
TypeError: test_empty_kwargs() got an unexpected keyword argument 'c'
"""
return
(
a
,
b
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment