public static ObjectType computeElementTypeOfExpression(ExecutionContext context,
      CompiledValue expr) throws AmbiguousNameException {
    try {

      ObjectType type = TypeUtils.OBJECT_TYPE;
      List exprSteps = new ArrayList();
      while (true) {
        if (expr instanceof CompiledPath) {
          CompiledPath path = (CompiledPath) expr;
          exprSteps.add(0, path.getTailID());
          expr = path.getReceiver();
        } else if (expr instanceof CompiledOperation) {
          CompiledOperation operation = (CompiledOperation) expr;
          if (operation.getArguments().size() > 0) {
            return TypeUtils.OBJECT_TYPE;
          }
          exprSteps.add(0, operation.getMethodName() + "()");
          expr = operation.getReceiver(context);
          if (expr == null) {
            expr = context.resolveImplicitOperationName(operation.getMethodName(),
                operation.getArguments().size(), true);
          }
        } else if (expr instanceof CompiledID) {
          expr = context.resolve(((CompiledID) expr).getId());
        } else if (expr instanceof CompiledRegion) {
          QRegion qrgn = (QRegion) ((CompiledRegion) expr).evaluate(context);
          type = qrgn.getCollectionType();
          break;
        } else if (expr instanceof RuntimeIterator) {
          type = ((RuntimeIterator) expr).getElementType();
          break;
        } else {
          return TypeUtils.OBJECT_TYPE;
        }
      }
      if (!TypeUtils.OBJECT_TYPE.equals(type)) {
        Class clazz = type.resolveClass();
        for (Object exprStep : exprSteps) {
          Member member;
          String stepStr = (String) exprStep;
          // System.out.println("step = "+step);
          if (stepStr.endsWith("()")) {
            stepStr = stepStr.substring(0, stepStr.length() - 2);
            member = clazz.getMethod(stepStr, (Class[]) null);
          } else {
            member = new AttributeDescriptor(context.getCache().getPdxRegistry(), stepStr)
                .getReadMember(clazz);
          }

          if (member instanceof Field) {
            clazz = ((Field) member).getType();
          } else if (member instanceof Method) {
            clazz = ((Method) member).getReturnType();
          }
          type = TypeUtils.getObjectType(clazz);
        }
        return type;
      }
    } catch (NoSuchMethodException ignored) {
    } catch (NameResolutionException ignored) {
    } catch (TypeMismatchException ignored) {
    }
    return TypeUtils.OBJECT_TYPE;
  }
@param pathArray the path starting with an attribute on the initial type.
@return array of types starting with the initialType and ending with the type of the last
        attribute in the path.
@throws NameNotFoundException if could not find an attribute along path
geode-core/src/main/java/org/apache/geode/cache/query/internal/PathUtils.java