Skip to content

Commit aed8e03

Browse files
Merge pull request RustPython#932 from youknowone/dict-unpacking
Add dict unpacking support for literal
2 parents 7727d09 + e12c681 commit aed8e03

File tree

6 files changed

+40
-8
lines changed

6 files changed

+40
-8
lines changed

parser/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ pub enum Expression {
195195
elements: Vec<Expression>,
196196
},
197197
Dict {
198-
elements: Vec<(Expression, Expression)>,
198+
elements: Vec<(Option<Expression>, Expression)>,
199199
},
200200
Set {
201201
elements: Vec<Expression>,

parser/src/python.lalrpop

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -833,8 +833,8 @@ TestListComp2: ast::Expression = {
833833
},
834834
};
835835

836-
TestDict: Vec<(ast::Expression, ast::Expression)> = {
837-
<elements:OneOrMore<DictEntry>> <_trailing_comma:","?> => elements,
836+
TestDict: Vec<(Option<ast::Expression>, ast::Expression)> = {
837+
<elements:OneOrMore<DictElement>> <_trailing_comma:","?> => elements,
838838
};
839839

840840
TestDictComp: ast::Expression = {
@@ -850,6 +850,11 @@ DictEntry: (ast::Expression, ast::Expression) = {
850850
<e1: Test> ":" <e2: Test> => (e1, e2),
851851
};
852852

853+
DictElement: (Option<ast::Expression>, ast::Expression) = {
854+
<e:DictEntry> => (Some(e.0), e.1),
855+
"**" <e:Expression> => (None, e),
856+
};
857+
853858
TestSet: Vec<ast::Expression> = {
854859
<e1:OneOrMore<Test>> ","? => e1
855860
};

tests/snippets/dict.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,10 @@ def __eq__(self, other):
191191

192192
assert {1: None, "b": None} == dict.fromkeys([1, "b"])
193193
assert {1: 0, "b": 0} == dict.fromkeys([1, "b"], 0)
194+
195+
x = {'a': 1, 'b': 1, 'c': 1}
196+
y = {'b': 2, 'c': 2, 'd': 2}
197+
z = {'c': 3, 'd': 3, 'e': 3}
198+
199+
w = {1: 1, **x, 2: 2, **y, 3: 3, **z, 4: 4}
200+
assert w == {1: 1, 'a': 1, 'b': 2, 'c': 3, 2: 2, 'd': 3, 3: 3, 'e': 3, 4: 4}

vm/src/compile.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,13 +1256,25 @@ impl Compiler {
12561256
}
12571257
ast::Expression::Dict { elements } => {
12581258
let size = elements.len();
1259+
let has_double_star = elements.iter().any(|e| e.0.is_none());
12591260
for (key, value) in elements {
1260-
self.compile_expression(key)?;
1261-
self.compile_expression(value)?;
1261+
if let Some(key) = key {
1262+
self.compile_expression(key)?;
1263+
self.compile_expression(value)?;
1264+
if has_double_star {
1265+
self.emit(Instruction::BuildMap {
1266+
size: 1,
1267+
unpack: false,
1268+
});
1269+
}
1270+
} else {
1271+
// dict unpacking
1272+
self.compile_expression(value)?;
1273+
}
12621274
}
12631275
self.emit(Instruction::BuildMap {
12641276
size,
1265-
unpack: false,
1277+
unpack: has_double_star,
12661278
});
12671279
}
12681280
ast::Expression::Slice { elements } => {

vm/src/stdlib/ast.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,11 @@ fn expression_to_ast(vm: &VirtualMachine, expression: &ast::Expression) -> PyRes
358358
let mut keys = Vec::new();
359359
let mut values = Vec::new();
360360
for (k, v) in elements {
361-
keys.push(expression_to_ast(vm, k)?.into_object());
361+
if let Some(k) = k {
362+
keys.push(expression_to_ast(vm, k)?.into_object());
363+
} else {
364+
keys.push(vm.ctx.none());
365+
}
362366
values.push(expression_to_ast(vm, v)?.into_object());
363367
}
364368

vm/src/symboltable.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,11 @@ impl SymbolTableBuilder {
404404
}
405405
ast::Expression::Dict { elements } => {
406406
for (key, value) in elements {
407-
self.scan_expression(key)?;
407+
if let Some(key) = key {
408+
self.scan_expression(key)?;
409+
} else {
410+
// dict unpacking marker
411+
}
408412
self.scan_expression(value)?;
409413
}
410414
}

0 commit comments

Comments
 (0)