Skip to content

Commit a6b2312

Browse files
authored
Merge pull request RustPython#1816 from RustPython/coolreader18/posonly-error
Error on positional-only parameters passed as keywords
2 parents 9108047 + aad2122 commit a6b2312

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

tests/snippets/function_args.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ def va2(*args, **kwargs):
4141
assert args == (5, 4)
4242
assert len(kwargs) == 0
4343

44-
4544
va2(5, 4)
4645
x = (5, 4)
4746
va2(*x)
@@ -114,3 +113,19 @@ def f(a):
114113
y = {'a': 2}
115114
with assert_raises(TypeError):
116115
f(**x, **y)
116+
117+
118+
def f(a, b, /, c, d, *, e, f):
119+
return a + b + c + d + e + f
120+
121+
assert f(1,2,3,4,e=5,f=6) == 21
122+
assert f(1,2,3,d=4,e=5,f=6) == 21
123+
assert f(1,2,c=3,d=4,e=5,f=6) == 21
124+
with assert_raises(TypeError):
125+
f(1,b=2,c=3,d=4,e=5,f=6)
126+
with assert_raises(TypeError):
127+
f(a=1,b=2,c=3,d=4,e=5,f=6)
128+
with assert_raises(TypeError):
129+
f(1,2,3,4,5,f=6)
130+
with assert_raises(TypeError):
131+
f(1,2,3,4,5,6)

vm/src/obj/objfunction.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use crate::pyobject::{
1515
};
1616
use crate::scope::Scope;
1717
use crate::slots::{SlotCall, SlotDescriptor};
18-
use crate::vm::VirtualMachine;
18+
use crate::VirtualMachine;
19+
use itertools::Itertools;
1920

2021
pub type PyFunctionRef = PyRef<PyFunction>;
2122

@@ -72,6 +73,7 @@ impl PyFunction {
7273
) -> PyResult<()> {
7374
let nargs = func_args.args.len();
7475
let nexpected_args = code_object.arg_names.len();
76+
let posonly_args = &code_object.arg_names[..code_object.posonlyarg_count];
7577

7678
// This parses the arguments from args and kwargs into
7779
// the proper variables keeping into account default values
@@ -126,12 +128,16 @@ impl PyFunction {
126128
bytecode::Varargs::None => None,
127129
};
128130

131+
let mut posonly_passed_as_kwarg = Vec::new();
129132
// Handle keyword arguments
130133
for (name, value) in func_args.kwargs {
131134
// Check if we have a parameter with this name:
132135
if code_object.arg_names.contains(&name) || code_object.kwonlyarg_names.contains(&name)
133136
{
134-
if locals.contains_key(&name, vm) {
137+
if posonly_args.contains(&name) {
138+
posonly_passed_as_kwarg.push(name);
139+
continue;
140+
} else if locals.contains_key(&name, vm) {
135141
return Err(
136142
vm.new_type_error(format!("Got multiple values for argument '{}'", name))
137143
);
@@ -146,6 +152,13 @@ impl PyFunction {
146152
);
147153
}
148154
}
155+
if !posonly_passed_as_kwarg.is_empty() {
156+
return Err(vm.new_type_error(format!(
157+
"{}() got some positional-only arguments passed as keyword arguments: '{}'",
158+
&code_object.obj_name,
159+
posonly_passed_as_kwarg.into_iter().format(", "),
160+
)));
161+
}
149162

150163
// Add missing positional arguments, if we have fewer positional arguments than the
151164
// function definition calls for

0 commit comments

Comments
 (0)