Rollback of commit 0d1dc5537903a8c2ad56e66cee129b8f4d4e2592.
--
PiperOrigin-RevId: 144194956
MOS_MIGRATED_REVID=144194956
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
index df93669..fc78da5 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkNestedSet.java
@@ -24,9 +24,12 @@
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
import com.google.devtools.build.lib.util.Preconditions;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
+import javax.annotation.Nullable;
/** A generic type safe NestedSet wrapper for Skylark. */
@SkylarkModule(
@@ -82,41 +85,47 @@
private final SkylarkType contentType;
private final NestedSet<?> set;
+ @Nullable
+ private final List<Object> items;
+ @Nullable
+ private final List<NestedSet> transitiveItems;
public SkylarkNestedSet(Order order, Object item, Location loc) throws EvalException {
- this(SkylarkType.TOP, item, loc, new NestedSetBuilder<Object>(order));
+ this(order, SkylarkType.TOP, item, loc, null);
}
public SkylarkNestedSet(SkylarkNestedSet left, Object right, Location loc) throws EvalException {
- this(
- left.contentType,
- right,
- loc,
- new NestedSetBuilder<Object>(left.getOrder()).addTransitive(left.set));
+ this(left.set.getOrder(), left.contentType, right, loc, left);
}
// This is safe because of the type checking
@SuppressWarnings("unchecked")
- private SkylarkNestedSet(
- SkylarkType contentType, Object item, Location loc, NestedSetBuilder setBuilder)
- throws EvalException {
+ private SkylarkNestedSet(Order order, SkylarkType contentType, Object item, Location loc,
+ @Nullable SkylarkNestedSet left) throws EvalException {
+
+ ArrayList<Object> items = new ArrayList<>();
+ ArrayList<NestedSet> transitiveItems = new ArrayList<>();
+ if (left != null) {
+ if (left.items == null) { // SkylarkSet created from native NestedSet
+ transitiveItems.add(left.set);
+ } else { // Preserving the left-to-right addition order.
+ items.addAll(left.items);
+ transitiveItems.addAll(left.transitiveItems);
+ }
+ }
// Adding the item
if (item instanceof SkylarkNestedSet) {
SkylarkNestedSet nestedSet = (SkylarkNestedSet) item;
if (!nestedSet.isEmpty()) {
contentType = checkType(contentType, nestedSet.contentType, loc);
- try {
- setBuilder.addTransitive((NestedSet<Object>) nestedSet.set);
- } catch (IllegalStateException e) {
- // Order mismatch between item and setBuilder.
- throw new EvalException(loc, e.getMessage());
- }
+ transitiveItems.add(nestedSet.set);
}
} else if (item instanceof SkylarkList) {
+ // TODO(bazel-team): we should check ImmutableList here but it screws up genrule at line 43
for (Object object : (SkylarkList) item) {
contentType = checkType(contentType, SkylarkType.of(object.getClass()), loc);
checkImmutable(object, loc);
- setBuilder.add(object);
+ items.add(object);
}
} else {
throw new EvalException(
@@ -125,7 +134,20 @@
"cannot add value of type '%s' to a depset", EvalUtils.getDataTypeName(item)));
}
this.contentType = Preconditions.checkNotNull(contentType, "type cannot be null");
- this.set = setBuilder.build();
+
+ // Initializing the real nested set
+ NestedSetBuilder<Object> builder = new NestedSetBuilder<>(order);
+ builder.addAll(items);
+ try {
+ for (NestedSet<?> nestedSet : transitiveItems) {
+ builder.addTransitive(nestedSet);
+ }
+ } catch (IllegalStateException e) {
+ throw new EvalException(loc, e.getMessage());
+ }
+ this.set = builder.build();
+ this.items = ImmutableList.copyOf(items);
+ this.transitiveItems = ImmutableList.copyOf(transitiveItems);
}
/**
@@ -150,6 +172,8 @@
// This is here for the sake of FuncallExpression.
this.contentType = Preconditions.checkNotNull(contentType, "type cannot be null");
this.set = Preconditions.checkNotNull(set, "set cannot be null");
+ this.items = null;
+ this.transitiveItems = null;
}
/**
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
index 913ae03..92d962a 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
@@ -871,7 +871,7 @@
@Test
public void testUnionSet() throws Exception {
new SkylarkTest()
- .testStatement("str(depset([1, 3]) | depset([1, 2]))", "set([1, 3, 2])")
+ .testStatement("str(depset([1, 3]) | depset([1, 2]))", "set([1, 2, 3])")
.testStatement("str(depset([1, 2]) | [1, 3])", "set([1, 2, 3])")
.testIfExactError("unsupported operand type(s) for |: 'int' and 'int'", "2 | 4");
}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java
index 3b155a7..967940d 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkNestedSetTest.java
@@ -14,12 +14,17 @@
package com.google.devtools.build.lib.syntax;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
-import java.util.Collection;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -47,25 +52,19 @@
@Test
public void testNsetOrder() throws Exception {
eval("n = depset(['a', 'b'], order='compile')");
- assertThat(get("n").getSet(String.class).getOrder()).isEqualTo(Order.COMPILE_ORDER);
+ assertEquals(Order.COMPILE_ORDER, get("n").getSet(String.class).getOrder());
}
@Test
public void testEmptyNsetGenericType() throws Exception {
eval("n = depset()");
- assertThat(get("n").getContentType()).isEqualTo(SkylarkType.TOP);
+ assertEquals(SkylarkType.TOP, get("n").getContentType());
}
@Test
public void testFunctionReturnsNset() throws Exception {
- eval(
- "def func():",
- " n = depset()",
- " n += ['a']",
- " return n",
- "s = func()");
- assertThat(get("s")).isInstanceOf(SkylarkNestedSet.class);
- assertThat(get("s").toCollection()).containsExactly("a");
+ eval("def func():", " n = depset()", " n += ['a']", " return n", "s = func()");
+ assertEquals(ImmutableList.of("a"), get("s").toCollection());
}
@Test
@@ -78,93 +77,21 @@
" n2 += ['b']",
" return n1",
"n = func()");
- assertThat(get("n").toCollection()).containsExactly("a");
+ assertEquals(ImmutableList.of("a"), get("n").toCollection());
}
@Test
- public void testNsetUnionOrder() throws Exception {
- // -----o----- []
- // / \
- // o ['a', 'b'] o ['b', 'c']
- // | |
- // o [] o []
+ public void testNsetNestedItem() throws Exception {
eval(
"def func():",
" n1 = depset()",
" n2 = depset()",
- " n1 += ['a', 'b']",
- " n2 += ['b', 'c']",
+ " n1 += ['a']",
+ " n2 += ['b']",
" n1 += n2",
" return n1",
"n = func()");
- // Under old behavior, the left operand was made a parent of the right operand. If that had
- // happened, then the post-order traversal would yield [b, c, a] rather than [a, b, c].
- assertThat(get("n").toCollection()).containsExactly("a", "b", "c").inOrder();
- }
-
- @Test
- public void testNsetMultiUnionOrder() throws Exception {
- // --------o-------- []
- // / \
- // ---o--- [] ---o--- []
- // / \ / \
- // o ['a'] o ['b'] o ['c'] o ['d']
- eval(
- "def func():",
- " na = depset(['a'], order='compile')",
- " nb = depset(['b'], order='compile')",
- " nc = depset(['c'], order='compile')",
- " nd = depset(['d'], order='compile')",
- " return na + nb + (nc + nd)",
- "n = func()");
- // Under old behavior, in a chain of three or more unions s1 + s2 + ... + sn (left-
- // associative), the post-order traversal yielded in order the elements of s2, s3, ..., sn, s1.
- // Now it should just be s1, ..., sn.
- assertThat(get("n").toCollection()).containsExactly("a", "b", "c", "d").inOrder();
- }
-
- @Test
- public void testNsetTransitiveOrder() throws Exception {
- // ---o--- []
- // / \
- // o ['a'] o ['b']
- // |
- // o ['c']
- eval(
- "def func():",
- " na = depset(['a'])",
- " nc = depset(['c'])",
- " nb = nc + ['b']",
- " return na + nb",
- "n = func()");
- assertThat(get("n").toCollection()).containsExactly("a", "c", "b").inOrder();
- }
-
- private Collection<Object> getDiamondTraversal(String order) throws Exception {
- // o ['a']
- // |
- // --o--
- // / \
- // o ['b'] o ['c']
- // \ /
- // --o-- ['d']
- initialize();
- eval(
- "def func():",
- " nd = depset(['d'], order='" + order + "')",
- " nb = nd + ['b']",
- " nc = nd + ['c']",
- " na = nb + nc + ['a']",
- " return na",
- "n = func()");
- return get("n").toCollection();
- }
-
- @Test
- public void testNsetDiamond() throws Exception {
- assertThat(getDiamondTraversal("compile")).containsExactly("d", "b", "c", "a").inOrder();
- assertThat(getDiamondTraversal("naive_link")).containsExactly("a", "b", "d", "c").inOrder();
- assertThat(getDiamondTraversal("link")).containsExactly("a", "b", "c", "d").inOrder();
+ assertEquals(ImmutableList.of("b", "a"), get("n").toCollection());
}
@Test
@@ -176,13 +103,8 @@
@Test
public void testNsetItemList() throws Exception {
- eval(
- "def func():",
- " n = depset()",
- " n += ['a', 'b']",
- " return n",
- "n = func()");
- assertThat(get("n").toCollection()).containsExactly("a", "b").inOrder();
+ eval("def func():", " n = depset()", " n += ['a', 'b']", " return n", "n = func()");
+ assertEquals(ImmutableList.of("a", "b"), get("n").toCollection());
}
@Test
@@ -196,7 +118,20 @@
" func1(n)",
" return n",
"n = func2()");
- assertThat(get("n").toCollection()).containsExactly("a");
+ assertEquals(ImmutableList.of("a"), get("n").toCollection());
+ }
+
+ @Test
+ public void testNsetTransitiveOrdering() throws Exception {
+ eval(
+ "def func():",
+ " na = depset(['a'], order='compile')",
+ " nb = depset(['b'], order='compile')",
+ " nc = depset(['c'], order='compile') + na",
+ " return depset() + nb + nc",
+ "n = func()");
+ // The iterator lists the Transitive sets first
+ assertEquals(ImmutableList.of("b", "a", "c"), get("n").toCollection());
}
@Test
@@ -210,7 +145,7 @@
" return na",
"n = func()");
// The iterator lists the Transitive sets first
- assertThat(get("n").toCollection()).containsExactly(4, 2, 3, 5).inOrder();
+ assertEquals(ImmutableList.of(4, 2, 3, 5), get("n").toCollection());
}
@Test
@@ -225,28 +160,14 @@
@Test
public void testNsetToString() throws Exception {
- // o [3, 4, 5]
- // |
- // o [2, 4, 6]
- // |
- // o []
- eval(
- "s = depset() + [2, 4, 6] + [3, 4, 5]",
- "x = str(s)");
- assertThat(lookup("x")).isEqualTo("set([2, 4, 6, 3, 5])");
+ eval("s = depset() + [2, 4, 6] + [3, 4, 5]", "x = str(s)");
+ assertEquals("set([2, 4, 6, 3, 5])", lookup("x"));
}
@Test
public void testNsetToStringWithOrder() throws Exception {
- // o [3, 4, 5]
- // |
- // o [2, 4, 6]
- // |
- // o []
- eval(
- "s = depset(order = 'link') + [2, 4, 6] + [3, 4, 5]",
- "x = str(s)");
- assertThat(lookup("x")).isEqualTo("set([3, 5, 2, 4, 6], order = \"link\")");
+ eval("s = depset(order = 'link') + [2, 4, 6] + [3, 4, 5]", "x = str(s)");
+ assertEquals("set([2, 4, 6, 3, 5], order = \"link\")", lookup("x"));
}
@SuppressWarnings("unchecked")
@@ -282,4 +203,100 @@
private boolean areOrdersCompatible(Order first, Order second) {
return first == Order.STABLE_ORDER || second == Order.STABLE_ORDER || first == second;
}
+
+ @Test
+ public void testSetOrderComplexUnion() throws Exception {
+ // {1, 11, {2, 22}, {3, 33}, {4, 44}}
+ List<String> preOrder = Arrays.asList("1", "11", "2", "22", "3", "33", "4", "44");
+ List<String> postOrder = Arrays.asList("2", "22", "3", "33", "4", "44", "1", "11");
+
+ MergeStrategy strategy = new MergeStrategy() {
+ @Override
+ public SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception {
+ SkylarkNestedSet union = new SkylarkNestedSet(sets[0], sets[1], null);
+ union = new SkylarkNestedSet(union, sets[2], null);
+ union = new SkylarkNestedSet(union, sets[3], null);
+
+ return union;
+ }
+ };
+
+ runComplexOrderTest(strategy, preOrder, postOrder);
+ }
+
+ @Test
+ public void testSetOrderBalancedTree() throws Exception {
+ // {{1, 11, {2, 22}}, {3, 33, {4, 44}}}
+ List<String> preOrder = Arrays.asList("1", "11", "2", "22", "3", "33", "4", "44");
+ List<String> postOrder = Arrays.asList("2", "22", "4", "44", "3", "33", "1", "11");
+
+ MergeStrategy strategy = new MergeStrategy() {
+ @Override
+ public SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception {
+ SkylarkNestedSet leftUnion = new SkylarkNestedSet(sets[0], sets[1], null);
+ SkylarkNestedSet rightUnion = new SkylarkNestedSet(sets[2], sets[3], null);
+ SkylarkNestedSet union = new SkylarkNestedSet(leftUnion, rightUnion, null);
+
+ return union;
+ }
+ };
+
+ runComplexOrderTest(strategy, preOrder, postOrder);
+ }
+
+ @Test
+ public void testSetOrderManyLevelsOfNesting() throws Exception {
+ // {1, 11, {2, 22, {3, 33, {4, 44}}}}
+ List<String> preOrder = Arrays.asList("1", "11", "2", "22", "3", "33", "4", "44");
+ List<String> postOrder = Arrays.asList("4", "44", "3", "33", "2", "22", "1", "11");
+
+ MergeStrategy strategy = new MergeStrategy() {
+ @Override
+ public SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception {
+ SkylarkNestedSet union = new SkylarkNestedSet(sets[2], sets[3], null);
+ union = new SkylarkNestedSet(sets[1], union, null);
+ union = new SkylarkNestedSet(sets[0], union, null);
+
+ return union;
+ }
+ };
+
+ runComplexOrderTest(strategy, preOrder, postOrder);
+ }
+
+ private interface MergeStrategy {
+ SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception;
+ }
+
+ private void runComplexOrderTest(
+ MergeStrategy strategy, List<String> preOrder, List<String> postOrder) throws Exception {
+ Map<Order, List<String>> expected = createExpectedMap(preOrder, postOrder);
+ for (Order order : Order.values()) {
+ SkylarkNestedSet union = strategy.merge(makeFourSets(order));
+ assertThat(union.toCollection()).containsExactlyElementsIn(expected.get(order)).inOrder();
+ }
+ }
+
+ private Map<Order, List<String>> createExpectedMap(
+ List<String> preOrder, List<String> postOrder) {
+ Map<Order, List<String>> expected = new HashMap<>();
+
+ for (Order order : Order.values()) {
+ expected.put(order, isPostOrder(order) ? postOrder : preOrder);
+ }
+
+ return expected;
+ }
+
+ private boolean isPostOrder(Order order) {
+ return order == Order.STABLE_ORDER || order == Order.COMPILE_ORDER;
+ }
+
+ private SkylarkNestedSet[] makeFourSets(Order order) throws Exception {
+ return new SkylarkNestedSet[] {
+ new SkylarkNestedSet(order, Tuple.of("1", "11"), null),
+ new SkylarkNestedSet(order, Tuple.of("2", "22"), null),
+ new SkylarkNestedSet(order, Tuple.of("3", "33"), null),
+ new SkylarkNestedSet(order, Tuple.of("4", "44"), null)};
+ }
}