Skip to content

Commit d56fcd0

Browse files
committed
DictUpdate instruction
1 parent 33ea50c commit d56fcd0

File tree

3 files changed

+29
-13
lines changed

3 files changed

+29
-13
lines changed

compiler/codegen/src/compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4398,7 +4398,7 @@ impl Compiler {
43984398

43994399
for item in unpacked {
44004400
self.compile_expression(&item.value)?;
4401-
emit!(self, Instruction::DictUpdate);
4401+
emit!(self, Instruction::DictUpdate { index: 1 });
44024402
}
44034403

44044404
Ok(())

compiler/core/src/bytecode.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,9 @@ pub enum Instruction {
667667
BuildMapForCall {
668668
size: Arg<u32>,
669669
},
670-
DictUpdate,
670+
DictUpdate {
671+
index: Arg<u32>,
672+
},
671673
BuildSlice {
672674
/// whether build a slice with a third step argument
673675
step: Arg<bool>,
@@ -1397,7 +1399,7 @@ impl Instruction {
13971399
let nargs = size.get(arg);
13981400
-(nargs as i32) + 1
13991401
}
1400-
DictUpdate => -1,
1402+
DictUpdate { .. } => -1,
14011403
BuildSlice { step } => -2 - (step.get(arg) as i32) + 1,
14021404
ListAppend { .. } | SetAdd { .. } => -1,
14031405
MapAdd { .. } => -2,
@@ -1586,7 +1588,7 @@ impl Instruction {
15861588
BuildSetFromTuples { size } => w!(BuildSetFromTuples, size),
15871589
BuildMap { size } => w!(BuildMap, size),
15881590
BuildMapForCall { size } => w!(BuildMapForCall, size),
1589-
DictUpdate => w!(DictUpdate),
1591+
DictUpdate { index } => w!(DictUpdate, index),
15901592
BuildSlice { step } => w!(BuildSlice, step),
15911593
ListAppend { i } => w!(ListAppend, i),
15921594
SetAdd { i } => w!(SetAdd, i),

vm/src/frame.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -800,26 +800,40 @@ impl ExecutingFrame<'_> {
800800
bytecode::Instruction::BuildMapForCall { size } => {
801801
self.execute_build_map_for_call(vm, size.get(arg))
802802
}
803-
bytecode::Instruction::DictUpdate => {
804-
let other = self.pop_value();
805-
let dict = self
806-
.top_value()
807-
.downcast_ref::<PyDict>()
808-
.expect("exact dict expected");
803+
bytecode::Instruction::DictUpdate { index } => {
804+
// Stack before: [..., dict, ..., source] (source at TOS)
805+
// Stack after: [..., dict, ...] (source consumed)
806+
// The dict to update is at position TOS-i (before popping source)
807+
808+
let idx = index.get(arg);
809+
810+
// Pop the source from TOS
811+
let source = self.pop_value();
812+
813+
// Get the dict to update (it's now at TOS-(i-1) after popping source)
814+
let dict = if idx <= 1 {
815+
// DICT_UPDATE 0 or 1: dict is at TOS (after popping source)
816+
self.top_value()
817+
} else {
818+
// DICT_UPDATE n: dict is at TOS-(n-1)
819+
self.nth_value(idx - 1)
820+
};
821+
822+
let dict = dict.downcast_ref::<PyDict>().expect("exact dict expected");
809823

810824
// For dictionary unpacking {**x}, x must be a mapping
811825
// Check if the object has the mapping protocol (keys method)
812826
if vm
813-
.get_method(other.clone(), vm.ctx.intern_str("keys"))
827+
.get_method(source.clone(), vm.ctx.intern_str("keys"))
814828
.is_none()
815829
{
816830
return Err(vm.new_type_error(format!(
817831
"'{}' object is not a mapping",
818-
other.class().name()
832+
source.class().name()
819833
)));
820834
}
821835

822-
dict.merge_object(other, vm)?;
836+
dict.merge_object(source, vm)?;
823837
Ok(None)
824838
}
825839
bytecode::Instruction::BuildSlice { step } => {

0 commit comments

Comments
 (0)