Skip to content

Commit a17456d

Browse files
committed
Raise TypeError for duplicate keyword arguments
1 parent df6acaf commit a17456d

File tree

4 files changed

+53
-7
lines changed

4 files changed

+53
-7
lines changed

bytecode/src/bytecode.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ pub enum Instruction {
243243
BuildMap {
244244
size: usize,
245245
unpack: bool,
246+
for_call: bool,
246247
},
247248
BuildSlice {
248249
size: usize,
@@ -519,7 +520,11 @@ impl Instruction {
519520
BuildTuple { size, unpack } => w!(BuildTuple, size, unpack),
520521
BuildList { size, unpack } => w!(BuildList, size, unpack),
521522
BuildSet { size, unpack } => w!(BuildSet, size, unpack),
522-
BuildMap { size, unpack } => w!(BuildMap, size, unpack),
523+
BuildMap {
524+
size,
525+
unpack,
526+
for_call,
527+
} => w!(BuildMap, size, unpack, for_call),
523528
BuildSlice { size } => w!(BuildSlice, size),
524529
ListAppend { i } => w!(ListAppend, i),
525530
SetAdd { i } => w!(SetAdd, i),

compiler/src/compile.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ impl<O: OutputStream> Compiler<O> {
658658
self.emit(Instruction::BuildMap {
659659
size: num_kw_only_defaults,
660660
unpack: false,
661+
for_call: false,
661662
});
662663
}
663664

@@ -896,6 +897,7 @@ impl<O: OutputStream> Compiler<O> {
896897
self.emit(Instruction::BuildMap {
897898
size: num_annotations,
898899
unpack: false,
900+
for_call: false,
899901
});
900902
}
901903

@@ -1464,6 +1466,7 @@ impl<O: OutputStream> Compiler<O> {
14641466
self.emit(Instruction::BuildMap {
14651467
size: subsize,
14661468
unpack: false,
1469+
for_call: false,
14671470
});
14681471
size += 1;
14691472
}
@@ -1472,10 +1475,15 @@ impl<O: OutputStream> Compiler<O> {
14721475
self.emit(Instruction::BuildMap {
14731476
size,
14741477
unpack: false,
1478+
for_call: false,
14751479
});
14761480
}
14771481
if size > 1 || has_unpacking {
1478-
self.emit(Instruction::BuildMap { size, unpack: true });
1482+
self.emit(Instruction::BuildMap {
1483+
size,
1484+
unpack: true,
1485+
for_call: false,
1486+
});
14791487
}
14801488
Ok(())
14811489
}
@@ -1704,12 +1712,17 @@ impl<O: OutputStream> Compiler<O> {
17041712
self.emit(Instruction::BuildMap {
17051713
size: subsize,
17061714
unpack: false,
1715+
for_call: false,
17071716
});
17081717
size += 1;
17091718
}
17101719
}
17111720
if size > 1 {
1712-
self.emit(Instruction::BuildMap { size, unpack: true });
1721+
self.emit(Instruction::BuildMap {
1722+
size,
1723+
unpack: true,
1724+
for_call: true,
1725+
});
17131726
}
17141727
Ok(())
17151728
}
@@ -1855,6 +1868,7 @@ impl<O: OutputStream> Compiler<O> {
18551868
self.emit(Instruction::BuildMap {
18561869
size: 0,
18571870
unpack: false,
1871+
for_call: false,
18581872
});
18591873
}
18601874
}

tests/snippets/function_args.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,12 @@ def inc(n):
105105

106106
with assert_raises(SyntaxError):
107107
exec("def f(a=1, b): pass")
108+
109+
110+
def f(a):
111+
pass
112+
113+
x = {'a': 1}
114+
y = {'a': 2}
115+
with assert_raises(TypeError):
116+
f(**x, **y)

vm/src/frame.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,11 @@ impl Frame {
284284
self.push_value(list_obj);
285285
Ok(None)
286286
}
287-
bytecode::Instruction::BuildMap { size, unpack } => {
288-
self.execute_build_map(vm, *size, *unpack)
289-
}
287+
bytecode::Instruction::BuildMap {
288+
size,
289+
unpack,
290+
for_call,
291+
} => self.execute_build_map(vm, *size, *unpack, *for_call),
290292
bytecode::Instruction::BuildSlice { size } => self.execute_build_slice(vm, *size),
291293
bytecode::Instruction::ListAppend { i } => {
292294
let list_obj = self.nth_value(*i);
@@ -809,13 +811,29 @@ impl Frame {
809811
Ok(None)
810812
}
811813

812-
fn execute_build_map(&self, vm: &VirtualMachine, size: usize, unpack: bool) -> FrameResult {
814+
fn execute_build_map(
815+
&self,
816+
vm: &VirtualMachine,
817+
size: usize,
818+
unpack: bool,
819+
for_call: bool,
820+
) -> FrameResult {
813821
let map_obj = vm.ctx.new_dict();
814822
if unpack {
815823
for obj in self.pop_multiple(size) {
816824
// Take all key-value pairs from the dict:
817825
let dict: PyDictRef = obj.downcast().expect("Need a dictionary to build a map.");
818826
for (key, value) in dict {
827+
if for_call {
828+
if map_obj.contains_key(&key, vm) {
829+
let key_repr = vm.to_repr(&key)?;
830+
let msg = format!(
831+
"got multiple values for keyword argument {}",
832+
key_repr.as_str()
833+
);
834+
return Err(vm.new_type_error(msg));
835+
}
836+
}
819837
map_obj.set_item(&key, value, vm).unwrap();
820838
}
821839
}

0 commit comments

Comments
 (0)