TINKERPOP-2965 Fixed bug in FilterRankingStrategy

This problem showed up in 3.5.6/3.6.3 after TINKERPOP-2919 which improved performance. The changes failed to properly propogate labels up from child traversals into the TraversalParent cache it created. As a result, labels started shifting around when they shouldn't have.
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 07f4ecb..0a1c88b 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@
 * Upgraded `gremlin-javascript` and `gremlint` to Node 16.20.0.
 * Upgraded `gremlin-go` to Go 1.20.
 * Improved the python `Translator` class with better handling for `P`, `None` and subclasses of `str`.
+* Fixed bug in `FilterRankingStrategy` that was preventing certain traversals from recognizing labels in child traversals.
 * Added `gremlin-java8.bat` file as a workaround to allow loading the console using Java 8 on Windows.
 * Fixed a bug in `gremlin-server` where timeout tasks were not cancelled and could cause very large memory usage when timeout is large.
 * Removed `jcabi-manifests` dependency from `gremlin-core`, `gremlin-driver`, and `gremlin-server`.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index 65723a2..9ebfeb7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -38,17 +38,15 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.javatuples.Pair;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 
 /**
@@ -83,20 +81,37 @@
             // traversals. This little cache keeps the effective data of that function which is if there is a
             // lambda in the children and the set of scope keys. note that the lambda sorta trumps the labels in
             // that if there is a lambda there's no real point to doing any sort of eval of the labels.
+            //
+            // this cache holds the parent and a pair. the first item in the pair is a boolean which is true if
+            // lambda is present and false otherwise. the second item in the pair is a set of labels from any
+            // Scoping steps
             final Map<TraversalParent, Pair<Boolean, Set<String>>> traversalParentCache = new HashMap<>();
             final Map<Step, Integer> stepRanking = new HashMap<>();
 
-            // build up the little cache
+            // gather the parents and their Scoping/LambdaHolder steps to build up the cache. since the traversal is
+            // processed in depth first manner, the entries gathered to m are deepest child first and held in order,
+            // so that the cache can be constructed with parent's knowing their children were processed first
             final Map<TraversalParent, List<Step<?,?>>> m =
-                    TraversalHelper.getStepsOfAssignableClassRecursively(traversal, Scoping.class, LambdaHolder.class).stream().
-                    collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent()));
+                    TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, TraversalParent.class).stream().
+                    collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent(), LinkedHashMap::new, Collectors.toList()));
+
+            // build the cache and use it to detect if any children impact the Pair in any way. in the case of a
+            // child with a lambda, the parent would simply inherit that true. in the case of additional labels they
+            // would just be appended to the list for the parent.
             m.forEach((k, v) -> {
-                final boolean hasLambda = v.stream().anyMatch(s -> s instanceof LambdaHolder);
+                final boolean hasLambda = v.stream().anyMatch(s -> s instanceof LambdaHolder ||
+                        (traversalParentCache.containsKey(s) && traversalParentCache.get(s).getValue0()));
                 if (hasLambda) {
                     traversalParentCache.put(k, Pair.with(true, Collections.emptySet()));
                 } else {
-                    traversalParentCache.put(k, Pair.with(false, v.stream().filter(s -> s instanceof Scoping).
-                            flatMap(s -> ((Scoping) s).getScopeKeys().stream()).collect(Collectors.toSet())));
+                    final Set<String> currentEntryScopeLabels = v.stream().filter(s -> s instanceof Scoping).
+                            flatMap(s -> ((Scoping) s).getScopeKeys().stream()).collect(Collectors.toSet());
+                    final Set<String> allScopeLabels = new HashSet<>(currentEntryScopeLabels);
+                    v.stream().filter(traversalParentCache::containsKey).forEach(s -> {
+                        final TraversalParent parent = (TraversalParent) s;
+                        allScopeLabels.addAll(traversalParentCache.get(parent).getValue1());
+                    });
+                    traversalParentCache.put(k, Pair.with(false, allScopeLabels));
                 }
             });
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
new file mode 100644
index 0000000..13eb36d
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.util;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+
+import java.util.Comparator;
+
+/**
+ * A {@code Comparator} that compares steps on the depth of the traversal that they are in.
+ */
+public final class DepthComparator implements Comparator<Step<?,?>> {
+
+    private static final DepthComparator instance = new DepthComparator();
+
+    private DepthComparator() {}
+
+    public static DepthComparator instance() {
+        return instance;
+    }
+
+    @Override
+    public int compare(final Step<?, ?> step1, final Step<?, ?> step2) {
+        return getDepth(step2) - getDepth(step1);
+    }
+
+    private int getDepth(final Step<?,?> step) {
+        return step == null || step instanceof EmptyStep ? 0 : getDepth((Step) step.getTraversal().getParent()) + 1;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index 9625a56..19117d6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -54,14 +54,17 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.Stack;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -313,6 +316,38 @@
         return list;
     }
 
+    /**
+     * Get steps of the specified classes throughout the traversal, collecting them in a fashion that orders them
+     * from the deepest steps first.
+     */
+    public static List<Step<?,?>> getStepsOfAssignableClassRecursivelyFromDepth(final Traversal.Admin<?, ?> traversal, final Class<?>... stepClasses) {
+        final List<Step<?,?>> list = new ArrayList<>();
+        final Stack<Step<?,?>> stack = new Stack<>();
+
+        traversal.getSteps().forEach(stack::push);
+
+        while (!stack.isEmpty()) {
+            final Step<?,?> current = stack.pop();
+            list.add(current);
+
+            if (current instanceof TraversalParent) {
+                ((TraversalParent) current).getLocalChildren().forEach(localChild -> localChild.getSteps().forEach(stack::push));
+                ((TraversalParent) current).getGlobalChildren().forEach(globalChild -> globalChild.getSteps().forEach(stack::push));
+            }
+        }
+
+        // sort by depth
+        list.sort(DepthComparator.instance());
+
+        return list.stream().filter(s -> {
+            for (Class<?> stepClass : stepClasses) {
+                if (stepClass.isAssignableFrom(s.getClass()))
+                    return true;
+            }
+            return false;
+        }).collect(Collectors.toList());
+    }
+
     public static boolean isGlobalChild(Traversal.Admin<?, ?> traversal) {
         while (!(traversal.isRoot())) {
             if (traversal.getParent().getLocalChildren().contains(traversal))
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
index 5e277ad..c788445 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
@@ -41,8 +41,6 @@
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
-import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.structure.PropertyType;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
@@ -446,4 +444,45 @@
         assertEquals(3, steps.stream().filter(s -> s instanceof VertexStep).count());
         assertEquals(1, steps.stream().filter(s -> s instanceof FoldStep).count());
     }
+
+    @Test
+    public void shouldGetStepsOfAssignableClassRecursivelyFromDepthNoTypes() {
+        final Traversal.Admin<?,?> traversal = __.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+        final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal);
+        assertEquals(0, steps.size());
+    }
+
+    @Test
+    public void shouldGetStepsOfAssignableClassRecursivelyFromDepthOneType() {
+        final Traversal.Admin<?,?> traversal = __.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+        final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, VertexStep.class);
+        assertEquals(3, steps.size());
+        assertThat(steps.stream().allMatch(s -> s instanceof VertexStep), is(true));
+    }
+
+    @Test
+    public void shouldGetStepsOfAssignableClassRecursivelyFromDepthMultipleTypes() {
+        final Traversal.Admin<?,?> traversal = __.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+        final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, VertexStep.class, FoldStep.class);
+        assertEquals(4, steps.size());
+        assertEquals(3, steps.stream().filter(s -> s instanceof VertexStep).count());
+        assertEquals(1, steps.stream().filter(s -> s instanceof FoldStep).count());
+    }
+
+    @Test
+    public void shouldGetStepsOfAssignableClassRecursivelyFromDepthEnsureOrder() {
+        final Traversal.Admin<?,?> traversal = __.V().union(
+                __.union(__.values("a"),
+                         __.union(__.values("b"), __.union(__.values("c"))),
+                         __.values("d")),
+                __.values("e")).values("f").asAdmin();
+        final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, PropertiesStep.class);
+        assertEquals(6, steps.size());
+        assertEquals("c", ((PropertiesStep) steps.get(0)).getPropertyKeys()[0]);
+        assertEquals("b", ((PropertiesStep) steps.get(1)).getPropertyKeys()[0]);
+        assertEquals("d", ((PropertiesStep) steps.get(2)).getPropertyKeys()[0]);
+        assertEquals("a", ((PropertiesStep) steps.get(3)).getPropertyKeys()[0]);
+        assertEquals("e", ((PropertiesStep) steps.get(4)).getPropertyKeys()[0]);
+        assertEquals("f", ((PropertiesStep) steps.get(5)).getPropertyKeys()[0]);
+    }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 5929439..030deae 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -333,6 +333,8 @@
                {"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a",P.Lt("b").Or(P.Gt("c")).And(P.Neq("d"))).By("age").By("weight").By(__.In("created").Values<object>("age").Min<object>()).Select<object>("a","c","d").By("name")}}, 
                {"g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out().Has("age").Where(P.Gt("a")).By("age").Values<object>("name")}}, 
                {"g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid3"]).As("a").In().Out().As("b").Where("a",P.Eq("b")).By("age").Values<object>("name")}}, 
+               {"g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("n").Where(__.Or(__.HasLabel("software"),__.HasLabel("person"))).Select<object>("n").By("name")}}, 
+               {"g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("n").Where(__.Or(__.Select<object>("n").HasLabel("software"),__.Select<object>("n").HasLabel("person"))).Select<object>("n").By("name")}}, 
                {"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a"), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).InE()}}, 
                {"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a").Property("weight",2.0), (g,p) =>g.E(), (g,p) =>g.V(p["vid1"]).BothE(), (g,p) =>g.V(p["vid1"]).InE().Has("weight",2.0)}}, 
                {"g_V_outE_propertyXweight_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh").AddV("software").Property(T.Id,5).Property("name","ripple").Property("lang","java").As("ripple").AddV("person").Property(T.Id,6).Property("name","peter").Property("age",35).As("peter").AddE("knows").From("marko").To("vadas").Property(T.Id,7).Property("weight",0.5).AddE("knows").From("marko").To("josh").Property(T.Id,8).Property("weight",1.0).AddE("created").From("marko").To("lop").Property(T.Id,9).Property("weight",0.4).AddE("created").From("josh").To("ripple").Property(T.Id,10).Property("weight",1.0).AddE("created").From("josh").To("lop").Property(T.Id,11).Property("weight",0.4).AddE("created").From("peter").To("lop").Property(T.Id,12).Property("weight",0.2), (g,p) =>g.V().OutE().Property("weight",null), (g,p) =>g.E().Properties<object>("weight")}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 24877ae..a6ddf27 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -304,6 +304,8 @@
     "g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a", gremlingo.P.Lt("b").Or(gremlingo.P.Gt("c")).And(gremlingo.P.Neq("d"))).By("age").By("weight").By(gremlingo.T__.In("created").Values("age").Min()).Select("a", "c", "d").By("name")}}, 
     "g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).As("a").Out().Has("age").Where(gremlingo.P.Gt("a")).By("age").Values("name")}}, 
     "g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid3"]).As("a").In().Out().As("b").Where("a", gremlingo.P.Eq("b")).By("age").Values("name")}}, 
+    "g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("n").Where(gremlingo.T__.Or(gremlingo.T__.HasLabel("software"), gremlingo.T__.HasLabel("person"))).Select("n").By("name")}}, 
+    "g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("n").Where(gremlingo.T__.Or(gremlingo.T__.Select("n").HasLabel("software"), gremlingo.T__.Select("n").HasLabel("person"))).Select("n").By("name")}}, 
     "g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property(gremlingo.T.Id, 4).Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property(gremlingo.T.Id, 5).Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property(gremlingo.T.Id, 6).Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property(gremlingo.T.Id, 7).Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property(gremlingo.T.Id, 8).Property("weight", 1.0).AddE("created").From("marko").To("lop").Property(gremlingo.T.Id, 9).Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property(gremlingo.T.Id, 10).Property("weight", 1.0).AddE("created").From("josh").To("lop").Property(gremlingo.T.Id, 11).Property("weight", 0.4).AddE("created").From("peter").To("lop").Property(gremlingo.T.Id, 12).Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).InE()}}, 
     "g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property(gremlingo.T.Id, 4).Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property(gremlingo.T.Id, 5).Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property(gremlingo.T.Id, 6).Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property(gremlingo.T.Id, 7).Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property(gremlingo.T.Id, 8).Property("weight", 1.0).AddE("created").From("marko").To("lop").Property(gremlingo.T.Id, 9).Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property(gremlingo.T.Id, 10).Property("weight", 1.0).AddE("created").From("josh").To("lop").Property(gremlingo.T.Id, 11).Property("weight", 0.4).AddE("created").From("peter").To("lop").Property(gremlingo.T.Id, 12).Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).As("a").Out("created").AddE("createdBy").To("a").Property("weight", 2.0)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).BothE()}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).InE().Has("weight", 2.0)}}, 
     "g_V_outE_propertyXweight_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property(gremlingo.T.Id, 4).Property("name", "josh").Property("age", 32).As("josh").AddV("software").Property(gremlingo.T.Id, 5).Property("name", "ripple").Property("lang", "java").As("ripple").AddV("person").Property(gremlingo.T.Id, 6).Property("name", "peter").Property("age", 35).As("peter").AddE("knows").From("marko").To("vadas").Property(gremlingo.T.Id, 7).Property("weight", 0.5).AddE("knows").From("marko").To("josh").Property(gremlingo.T.Id, 8).Property("weight", 1.0).AddE("created").From("marko").To("lop").Property(gremlingo.T.Id, 9).Property("weight", 0.4).AddE("created").From("josh").To("ripple").Property(gremlingo.T.Id, 10).Property("weight", 1.0).AddE("created").From("josh").To("lop").Property(gremlingo.T.Id, 11).Property("weight", 0.4).AddE("created").From("peter").To("lop").Property(gremlingo.T.Id, 12).Property("weight", 0.2)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().OutE().Property("weight", nil)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Properties("weight")}}, 
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 680ce38..2dd768e 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -321,6 +321,8 @@
     g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX: [function({g}) { return g.V().as("a").outE("created").as("b").inV().as("c").in_("created").as("d").where("a",P.lt("b").or(P.gt("c")).and(P.neq("d"))).by("age").by("weight").by(__.in_("created").values("age").min()).select("a","c","d").by("name") }], 
     g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name: [function({g, vid1}) { return g.V(vid1).as("a").out().has("age").where(P.gt("a")).by("age").values("name") }], 
     g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name: [function({g, vid3}) { return g.V(vid3).as("a").in_().out().as("b").where("a",P.eq("b")).by("age").values("name") }], 
+    g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX: [function({g}) { return g.V().as("n").where(__.or(__.hasLabel("software"),__.hasLabel("person"))).select("n").by("name") }], 
+    g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX: [function({g}) { return g.V().as("n").where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person"))).select("n").by("name") }], 
     g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1}) { return g.V(vid1).as("a").out("created").addE("createdBy").to("a") }, function({g, vid1}) { return g.E() }, function({g, vid1}) { return g.V(vid1).inE() }], 
     g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g, vid1}) { return g.V(vid1).as("a").out("created").addE("createdBy").to("a").property("weight",2.0) }, function({g, vid1}) { return g.E() }, function({g, vid1}) { return g.V(vid1).bothE() }, function({g, vid1}) { return g.V(vid1).inE().has("weight",2.0) }], 
     g_V_outE_propertyXweight_nullX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang","java").as("ripple").addV("person").property(T.id,6).property("name","peter").property("age",35).as("peter").addE("knows").from_("marko").to("vadas").property(T.id,7).property("weight",0.5).addE("knows").from_("marko").to("josh").property(T.id,8).property("weight",1.0).addE("created").from_("marko").to("lop").property(T.id,9).property("weight",0.4).addE("created").from_("josh").to("ripple").property(T.id,10).property("weight",1.0).addE("created").from_("josh").to("lop").property(T.id,11).property("weight",0.4).addE("created").from_("peter").to("lop").property(T.id,12).property("weight",0.2) }, function({g}) { return g.V().outE().property("weight",null) }, function({g}) { return g.E().properties("weight") }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 6397b76..a57daf0 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -306,6 +306,8 @@
     'g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX': [(lambda g:g.V().as_('a').outE('created').as_('b').inV().as_('c').in_('created').as_('d').where('a',P.lt('b').or_(P.gt('c')).and_(P.neq('d'))).by('age').by('weight').by(__.in_('created').age.min_()).select('a','c','d').by('name'))], 
     'g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name': [(lambda g, vid1=None:g.V(vid1).as_('a').out().has('age').where(P.gt('a')).by('age').name)], 
     'g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name': [(lambda g, vid3=None:g.V(vid3).as_('a').in_().out().as_('b').where('a',P.eq('b')).by('age').name)], 
+    'g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX': [(lambda g:g.V().as_('n').where(__.or_(__.hasLabel('software'),__.hasLabel('person'))).select('n').by('name'))], 
+    'g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX': [(lambda g:g.V().as_('n').where(__.or_(__.select('n').hasLabel('software'),__.select('n').hasLabel('person'))).select('n').by('name'))], 
     'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX': [(lambda g, vid1=None:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id_,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id_,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id_,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id_,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id_,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id_,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id_,12).property('weight',float(0.2))), (lambda g, vid1=None:g.V(vid1).as_('a').out('created').addE('createdBy').to('a')), (lambda g, vid1=None:g.E()), (lambda g, vid1=None:g.V(vid1).inE())], 
     'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X': [(lambda g, vid1=None:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id_,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id_,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id_,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id_,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id_,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id_,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id_,12).property('weight',float(0.2))), (lambda g, vid1=None:g.V(vid1).as_('a').out('created').addE('createdBy').to('a').property('weight',float(2.0))), (lambda g, vid1=None:g.E()), (lambda g, vid1=None:g.V(vid1).bothE()), (lambda g, vid1=None:g.V(vid1).inE().has('weight',float(2.0)))], 
     'g_V_outE_propertyXweight_nullX': [(lambda g:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name','ripple').property('lang','java').as_('ripple').addV('person').property(T.id_,6).property('name','peter').property('age',35).as_('peter').addE('knows').from_('marko').to('vadas').property(T.id_,7).property('weight',float(0.5)).addE('knows').from_('marko').to('josh').property(T.id_,8).property('weight',float(1.0)).addE('created').from_('marko').to('lop').property(T.id_,9).property('weight',float(0.4)).addE('created').from_('josh').to('ripple').property(T.id_,10).property('weight',float(1.0)).addE('created').from_('josh').to('lop').property(T.id_,11).property('weight',float(0.4)).addE('created').from_('peter').to('lop').property(T.id_,12).property('weight',float(0.2))), (lambda g:g.V().outE().property('weight',None)), (lambda g:g.E().properties('weight'))], 
diff --git a/gremlin-test/features/filter/Where.feature b/gremlin-test/features/filter/Where.feature
index f4e8f9b..4a68b5a 100644
--- a/gremlin-test/features/filter/Where.feature
+++ b/gremlin-test/features/filter/Where.feature
@@ -338,4 +338,40 @@
       | lop |
       | lop |
       | lop |
+      | ripple |
+
+  Scenario: g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().as("n").where(
+        __.or(__.hasLabel("software"), __.hasLabel("person"))
+      ).select("n").by("name")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | josh |
+      | peter |
+      | lop |
+      | ripple |
+
+  Scenario: g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().as("n").
+        where(__.or(__.select("n").hasLabel("software"), __.select("n").hasLabel("person"))).
+        select("n").by("name")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | josh |
+      | peter |
+      | lop |
       | ripple |
\ No newline at end of file