private boolean checkSemantic(Collection<Object> elements1, Collection<Object> elements2) {
        if (elements1.size() != elements2.size()) {
            return false;
        }
        Iterator it1 = elements1.iterator();
        Iterator it2 = elements2.iterator();
        while (it1.hasNext()) {
            Object e1 = it1.next();
            Object e2 = it2.next();
            if (e1 == e2) {
                continue;
            }
            if (e1 == null || e2 == null) {
                return false;
            }
            if (e1 instanceof Expression && e2 instanceof Expression) {
                if (!((Expression) e1).semanticEquals((Expression) e2)) {
                    return false;
                }
            }
            if (e1 instanceof Collection && e2 instanceof Collection) {
                if (!checkSemantic((Collection) e1, (Collection) e2)) {
                    return false;
                }
            }
        }
        return true;
    }
Returns true when an expression is a candidate for static evaluation before the query is
executed.

The following conditions are used to determine suitability for constant folding:
- A [[Coalesce]] is foldable if all of its children are foldable
- A [[BinaryExpression]] is foldable if its both left and right child are foldable
- A [[Not]], [[IsNull]], or [[IsNotNull]] is foldable if its child is foldable
- A [[Literal]] is foldable
- A [[Cast]] or [[UnaryMinus]] is foldable if its child is foldable
indexr-query-opt/src/main/java/io/indexr/query/expr/Expression.java