public void addIds(final Object... newIds) {
        // there is some logic that has been around for a long time that used to set ids to null. it only happened here
        // in this method and only occurred when the ids were already null or empty and the newIds were length 1 and
        // an instance of List and that list was empty. so basically it would trigger for something like g.V().hasId([])
        // which in turn would trigger an empty iterator in TinkerGraphStep and zero results. trying to maintain that
        // logic now with GValue in the mix is tough because the context of what the meaning is gets lost by the time
        // you get to calling getResolvedIds(). using a flag to try to maintain that legacy logic, but ultimately, all
        // this needs to be rethought.
        this.legacyLogicForPassingNoIds = newIds.length == 1 && ((newIds[0] instanceof List && ((List) newIds[0]).isEmpty()) ||
                (newIds[0] instanceof GValue && ((GValue) newIds[0]).getType().isCollection() && ((List) ((GValue) newIds[0]).get()).isEmpty()));

        final GValue[] gvalues = GValue.ensureGValues(tryUnrollSingleCollectionArgument(newIds));
        this.ids = ArrayUtils.addAll(this.ids, gvalues);
    }
Gets the ids associated with this step as literal values rather than {@link GValue} objects.
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GraphStep.java