[operators] Add scope comparison to list subtraction.

Makes lists of scopes behave the same as lists of ints/bools/strings
when subtracting.

Bug: crbug.com/gn/17
Change-Id: I92c6d658d8b15246f7a53f602b6de4d0aa77ee43
Reviewed-on: https://gn-review.googlesource.com/c/3080
Commit-Queue: Julie Hockett <juliehockett@google.com>
Reviewed-by: Scott Graham <scottmg@chromium.org>
diff --git a/tools/gn/operators.cc b/tools/gn/operators.cc
index b5227f4..33fbcb2 100644
--- a/tools/gn/operators.cc
+++ b/tools/gn/operators.cc
@@ -283,7 +283,8 @@
   switch (to_remove.type()) {
     case Value::BOOLEAN:
     case Value::INTEGER:  // Filter out the individual int/string.
-    case Value::STRING: {
+    case Value::STRING:
+    case Value::SCOPE: {
       bool found_match = false;
       for (size_t i = 0; i < v.size(); /* nothing */) {
         if (v[i] == to_remove) {
diff --git a/tools/gn/operators_unittest.cc b/tools/gn/operators_unittest.cc
index 7e27fad..db90ac9 100644
--- a/tools/gn/operators_unittest.cc
+++ b/tools/gn/operators_unittest.cc
@@ -232,6 +232,45 @@
   EXPECT_EQ("bar", new_value->list_value()[0].string_value());
 }
 
+TEST(Operators, ListSubtractWithScope) {
+  Err err;
+  TestWithScope setup;
+
+  Scope* scope_a = new Scope(setup.settings());
+  Value scopeval_a(nullptr, std::unique_ptr<Scope>(scope_a));
+  scope_a->SetValue("a", Value(nullptr, "foo"), nullptr);
+
+  Scope* scope_b = new Scope(setup.settings());
+  Value scopeval_b(nullptr, std::unique_ptr<Scope>(scope_b));
+  scope_b->SetValue("b", Value(nullptr, "bar"), nullptr);
+
+  Value lval(nullptr, Value::LIST);
+  lval.list_value().push_back(scopeval_a);
+  lval.list_value().push_back(scopeval_b);
+
+  Scope* scope_a_other = new Scope(setup.settings());
+  Value scopeval_a_other(nullptr, std::unique_ptr<Scope>(scope_a_other));
+  scope_a_other->SetValue("a", Value(nullptr, "foo"), nullptr);
+
+  Value rval(nullptr, Value::LIST);
+  rval.list_value().push_back(scopeval_a_other);
+
+  TestBinaryOpNode node(Token::MINUS, "-");
+  node.SetLeftToValue(lval);
+  node.SetRightToValue(rval);
+  Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
+                                    node.right(), &err);
+  ASSERT_FALSE(err.has_error());
+  ASSERT_EQ(Value::LIST, ret.type());
+
+  std::vector<Value> expected;
+  Scope* scope_expected = new Scope(setup.settings());
+  Value scopeval_expected(nullptr, std::unique_ptr<Scope>(scope_expected));
+  scope_expected->SetValue("b", Value(nullptr, "bar"), nullptr);
+  expected.push_back(scopeval_expected);
+  EXPECT_EQ(expected, ret.list_value());
+}
+
 TEST(Operators, IntegerAdd) {
   Err err;
   TestWithScope setup;