Commit b4f8fd7e authored by Stefan Behnel's avatar Stefan Behnel

prevent PEP448 dict unpacking from leaking into first argument if it's a dict

parent 8b41a547
......@@ -5563,9 +5563,17 @@ class MergedDictNode(ExprNode):
code.putln('if (likely(PyDict_CheckExact(%s))) {' %
item.py_result())
item.make_owned_reference(code)
code.putln("%s = %s;" % (self.result(), item.py_result()))
item.generate_post_assignment_code(code)
if item.is_dict_literal:
item.make_owned_reference(code)
code.putln("%s = %s;" % (self.result(), item.py_result()))
item.generate_post_assignment_code(code)
else:
code.putln("%s = PyDict_Copy(%s); %s" % (
self.result(),
item.py_result(),
code.error_goto_if_null(self.result(), item.pos)))
code.put_gotref(self.result())
item.generate_disposal_code(code)
if item.type is not dict_type:
code.putln('} else {')
......
......@@ -117,6 +117,33 @@ def unpack_tuple_from_iterable(it):
return (1, 2, *it, 1, *(*it, *it), *it, 2, 1, *it)
def unpack_tuple_keep_originals(a, b, c):
"""
>>> a = b = [1, 2]
>>> c = [3, 4]
>>> unpack_tuple_keep_originals(a, b, c)
(1, 2, 1, 2, 2, 3, 4)
>>> a
[1, 2]
>>> b
[1, 2]
>>> c
[3, 4]
>>> a = b = (1, 2)
>>> c = (3, 4)
>>> unpack_tuple_keep_originals(a, b, c)
(1, 2, 1, 2, 2, 3, 4)
>>> a
(1, 2)
>>> b
(1, 2)
>>> c
(3, 4)
"""
return (*a, *b, 2, *c)
#### lists
......@@ -211,6 +238,22 @@ def unpack_list_from_iterable(it):
return [1, 2, *it, 1, *[*it, *it], *it, 2, 1, *it]
def unpack_list_keep_originals(a, b, c):
"""
>>> a = b = [1, 2]
>>> c = [3, 4]
>>> unpack_list_keep_originals(a, b, c)
[1, 2, 1, 2, 2, 3, 4]
>>> a
[1, 2]
>>> b
[1, 2]
>>> c
[3, 4]
"""
return [*a, *b, 2, *c]
###### sets
......@@ -321,6 +364,23 @@ def unpack_set_from_iterable(it):
return {1, 2, *it, 1, *{*it, *it}, *it, 2, 1, *it, *it}
def unpack_set_keep_originals(a, b, c):
"""
>>> a = b = {1, 2}
>>> c = {3, 4}
>>> s = unpack_set_keep_originals(a, b, c)
>>> s == set([1, 2, 3, 4]) or s
True
>>> a == set([1, 2]) or a
True
>>> b == set([1, 2]) or b
True
>>> c == set([3, 4]) or c
True
"""
return {*a, *b, 2, *c}
#### dicts
......@@ -441,3 +501,20 @@ def unpack_dict_from_iterable(it):
True
"""
return {'a': 2, 'b': 3, **it, 'a': 1, **{**it, **it}, **it, 'a': 4, 'b': 5, **it, **it}
def unpack_dict_keep_originals(a, b, c):
"""
>>> a = b = {1: 2}
>>> c = {2: 3, 4: 5}
>>> d = unpack_dict_keep_originals(a, b, c)
>>> d == {1: 2, 2: 3, 4: 5} or d
True
>>> a
{1: 2}
>>> b
{1: 2}
>>> c == {2: 3, 4: 5} or c
True
"""
return {**a, **b, 2: 4, **c}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment