@Override
 public boolean enterCallNode(final CallNode callNode) {
   curExpr = null;
   callNode.getFunction().accept(this);
   final ExpressionTree funcTree = curExpr;
   final List<? extends ExpressionTree> argTrees = translateExprs(callNode.getArgs());
   curExpr = new FunctionCallTreeImpl(callNode, funcTree, argTrees);
   return false;
 }
 @Override
 public boolean enterCallNode(final CallNode callNode) {
   tagNeverOptimistic(callNode.getFunction());
   return true;
 }
  private Type getEvaluatedType(final Optimistic expr) {
    if (expr instanceof IdentNode) {
      if (runtimeScope == null) {
        return null;
      }
      return getPropertyType(runtimeScope, ((IdentNode) expr).getName());
    } else if (expr instanceof AccessNode) {
      final AccessNode accessNode = (AccessNode) expr;
      final Object base = evaluateSafely(accessNode.getBase());
      if (!(base instanceof ScriptObject)) {
        return null;
      }
      return getPropertyType((ScriptObject) base, accessNode.getProperty());
    } else if (expr instanceof IndexNode) {
      final IndexNode indexNode = (IndexNode) expr;
      final Object base = evaluateSafely(indexNode.getBase());
      if (base instanceof NativeArray || base instanceof ArrayBufferView) {
        // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of
        // their
        // underlying array storage, not based on values of individual elements. Thus, a
        // LongArrayData will
        // throw UOE for every optimistic int linkage attempt, even if the long value being returned
        // in the
        // first invocation would be representable as int. That way, we can presume that the array's
        // optimistic
        // type is the most optimistic type for which an element getter has a chance of executing
        // successfully.
        return ((ScriptObject) base).getArray().getOptimisticType();
      }
    } else if (expr instanceof CallNode) {
      // Currently, we'll only try to guess the return type of immediately invoked function
      // expressions with no
      // parameters, that is (function() { ... })(). We could do better, but these are all
      // heuristics and we can
      // gradually introduce them as needed. An easy one would be to do the same for .call(this)
      // idiom.
      final CallNode callExpr = (CallNode) expr;
      final Expression fnExpr = callExpr.getFunction();
      if (fnExpr instanceof FunctionNode) {
        final FunctionNode fn = (FunctionNode) fnExpr;
        if (callExpr.getArgs().isEmpty()) {
          final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
          if (data != null) {
            final Type returnType =
                Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
            if (returnType == Type.BOOLEAN) {
              // We don't have optimistic booleans. In fact, optimistic call sites getting back
              // boolean
              // currently deoptimize all the way to Object.
              return Type.OBJECT;
            }
            assert returnType == Type.INT
                || returnType == Type.LONG
                || returnType == Type.NUMBER
                || returnType == Type.OBJECT;
            return returnType;
          }
        }
      }
    }

    return null;
  }