(final CompileContext cc)
| 163 | } |
| 164 | |
| 165 | @Override |
| 166 | public Expr optimize(final CompileContext cc) { |
| 167 | cc.pushScope(vs); |
| 168 | try { |
| 169 | // inline all values in the closure |
| 170 | final Iterator<Entry<Var, Expr>> iter = global.entrySet().iterator(); |
| 171 | Map<Var, Expr> add = null; |
| 172 | final int limit = cc.qc.context.options.get(MainOptions.INLINELIMIT); |
| 173 | while(iter.hasNext()) { |
| 174 | final Entry<Var, Expr> entry = iter.next(); |
| 175 | final Var var = entry.getKey(); |
| 176 | final Expr ex = entry.getValue(); |
| 177 | |
| 178 | Expr inline = null; |
| 179 | if(ex instanceof final Value value) { |
| 180 | // values are always inlined into the closure |
| 181 | inline = var.checkType(value, cc.qc, cc); |
| 182 | } else if(ex instanceof final Closure cl) { |
| 183 | // nested closures are inlined if their size and number of closed-over variables is small |
| 184 | if(!cl.has(Flag.NDT) && cl.global.size() < 5 |
| 185 | && expr.count(var) != VarUsage.MORE_THAN_ONCE && cl.exprSize() < limit) { |
| 186 | cc.info(OPTINLINE_X, entry); |
| 187 | for(final Entry<Var, Expr> expr2 : cl.global.entrySet()) { |
| 188 | final Var var2 = cc.copy(expr2.getKey(), null); |
| 189 | if(add == null) add = new HashMap<>(); |
| 190 | add.put(var2, expr2.getValue()); |
| 191 | expr2.setValue(new VarRef(cl.info, var2).optimize(cc)); |
| 192 | } |
| 193 | inline = cl; |
| 194 | } |
| 195 | } |
| 196 | if(inline != null) { |
| 197 | expr = new InlineContext(var, inline, cc).inline(expr); |
| 198 | iter.remove(); |
| 199 | } |
| 200 | } |
| 201 | // add all newly added bindings |
| 202 | if(add != null) global.putAll(add); |
| 203 | } catch(final QueryException ex) { |
| 204 | expr = FnError.get(ex, expr); |
| 205 | } finally { |
| 206 | cc.removeScope(this); |
| 207 | } |
| 208 | |
| 209 | final SeqType st = expr.seqType(); |
| 210 | final SeqType dt = declType == null || st.instanceOf(declType) ? st : declType; |
| 211 | exprType.assign(FuncType.get(anns, dt, params)); |
| 212 | |
| 213 | // only evaluate if: |
| 214 | // - the closure is empty, so we don't lose variables |
| 215 | // - the result size is not too large |
| 216 | if(global.isEmpty() && !cc.largeResult(expr)) { |
| 217 | try { |
| 218 | return cc.preEval(this); |
| 219 | } catch(final QueryException ex) { |
| 220 | expr = FnError.get(ex, expr); |
| 221 | } |
| 222 | } |
no test coverage detected