| 35 | } |
| 36 | |
| 37 | @Override |
| 38 | Expr opt(final CompileContext cc) throws QueryException { |
| 39 | flatten(cc); |
| 40 | |
| 41 | // determine type |
| 42 | SeqType st = SeqType.union(exprs, false); |
| 43 | if(st == null) st = Types.GNODE_ZM; |
| 44 | if(!(st.type instanceof NodeType)) return null; |
| 45 | |
| 46 | exprType.assign(st.union(Occ.ONE_OR_MORE)).data(exprs); |
| 47 | |
| 48 | final ExprList list = new ExprList(exprs.length); |
| 49 | for(final Expr expr : exprs) { |
| 50 | if(expr == Empty.VALUE || list.contains(expr) && !expr.has(Flag.CNS, Flag.NDT)) { |
| 51 | // remove empty operands: * union () → * |
| 52 | // remove duplicates: * union * → * |
| 53 | cc.info(OPTREMOVE_X_X, expr, (Supplier<?>) this::description); |
| 54 | } else { |
| 55 | list.add(expr); |
| 56 | } |
| 57 | } |
| 58 | exprs = list.finish(); |
| 59 | |
| 60 | final Expr ex = rewrite(Intersect.class, (invert, ops) -> |
| 61 | invert ? new Intersect(info, ops) : new Union(info, ops), cc); |
| 62 | if(ex != null) { |
| 63 | cc.info(OPTREWRITE_X_X, (Supplier<?>) this::description, ex); |
| 64 | return ex; |
| 65 | } |
| 66 | return null; |
| 67 | } |
| 68 | |
| 69 | @Override |
| 70 | Or mergePredicates(final Expr[] preds, final CompileContext cc) { |