Revert "eval: remove deprecated dict+dict operator (#54)" (#71)
This reverts commit 345cac49c6fe34e03558fbc9c7413401ede9252:
This operator is deprecated but still widely used by Bazel.
diff --git a/doc/spec.md b/doc/spec.md
index 780d83a..a15c273 100644
--- a/doc/spec.md
+++ b/doc/spec.md
@@ -787,6 +787,13 @@
A dictionary used in a Boolean context is considered true if it is
non-empty.
+The binary `+` operation may be applied to two dictionaries. It
+yields a new dictionary whose elements are the union of the two
+operands. If a key is present in both operands, the result contains
+the value from the right operand.
+<b>Note:</b> this feature is deprecated. Use the
+`dict.update` method instead.
+
Dictionaries may be compared for equality using `==` and `!=`. Two
dictionaries compare equal if they contain the same number of items
and each key/value item (k, v) found in one dictionary is also present
@@ -1795,6 +1802,7 @@
string + string
list + list
tuple + tuple
+ dict + dict # (deprecated)
Repetition (string/list/tuple)
int * sequence
@@ -1826,6 +1834,15 @@
[1, 2] + [3, 4] # [1, 2, 3, 4]
```
+The `x + y` operation is deprecated for `dict` operands; see Google Issue b/31994014.
+Use the [dict·update](dict·update) method instead:
+
+```python
+# z = x + y
+z = dict(x)
+z.update(y)
+```
+
The `*` operator may be applied to an integer _n_ and a value of type
`string`, `list`, or `tuple`, in which case it yields a new value
of the same sequence type consisting of _n_ repetitions of the original sequence.
diff --git a/eval.go b/eval.go
index 132c66d..d99c363 100644
--- a/eval.go
+++ b/eval.go
@@ -953,6 +953,21 @@
z = append(z, y...)
return z, nil
}
+ case *Dict:
+ // Python doesn't have dict+dict, and I can't find
+ // it documented for Skylark. But it is used; see:
+ // tools/build_defs/haskell/def.bzl:448
+ // TODO(adonovan): clarify spec; see b/36360157.
+ if y, ok := y.(*Dict); ok {
+ z := new(Dict)
+ for _, item := range x.Items() {
+ z.Set(item[0], item[1])
+ }
+ for _, item := range y.Items() {
+ z.Set(item[0], item[1])
+ }
+ return z, nil
+ }
}
case syntax.MINUS:
diff --git a/testdata/dict.sky b/testdata/dict.sky
index 15b36be..e948e72 100644
--- a/testdata/dict.sky
+++ b/testdata/dict.sky
@@ -11,8 +11,8 @@
assert.true({False: False})
assert.true(not {})
-# dict + dict is no longer supported; use dict.update.
-assert.fails(lambda: {} + {}, r'unknown binary op: dict \+ dict')
+# dict + dict (undocumented and deprecated; see b/36360157).
+assert.eq({"a": 1, "b": 2} + {"a": 3, "c": 4}, {"a": 3, "b": 2, "c": 4})
# dict comprehension
assert.eq({x: x*x for x in range(3)}, {0: 0, 1: 1, 2: 4})