protected ClassNode getResultType()

in src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java [4630:4749]


    protected ClassNode getResultType(ClassNode left, final int op, final ClassNode right, final BinaryExpression expr) {
        ClassNode leftRedirect = left.redirect();
        ClassNode rightRedirect = right.redirect();

        Expression leftExpression = expr.getLeftExpression();
        Expression rightExpression = expr.getRightExpression();

        if (op == EQUAL || op == ELVIS_EQUAL) {
            if (leftExpression instanceof VariableExpression) {
                ClassNode initialType = getOriginalDeclarationType(leftExpression);
                if (isDynamicTyped(initialType)) { // GROOVY-11353, GROOVY-11375
                    ClassNode inferredType = leftExpression.getNodeMetaData(INFERRED_TYPE);
                    if (inferredType != null ? !isPrimitiveType(inferredType) : Boolean.TRUE.equals(initialType.getNodeMetaData("non-primitive type"))) {
                        initialType = OBJECT_TYPE;
                    }
                }

                if (isPrimitiveType(rightRedirect) && (initialType.isDerivedFrom(Number_TYPE) || (isObjectType(initialType) && !isDynamicTyped(initialType)))) {
                    return getWrapper(right);
                }

                if (isPrimitiveType(initialType) && (isNumberType(initialType) ? rightRedirect.isDerivedFrom(Number_TYPE) : rightRedirect == getWrapper(initialType))) { // GROOVY-10359, GROOVY-6574
                    return getUnwrapper(right);
                }

                // as anything can be assigned to a String, Class or [Bb]oolean, return the left type instead
                if (isWildcardLeftHandSide(initialType) && !isObjectType(initialType)) {
                    return initialType;
                }
            }

            if (!isObjectType(leftRedirect)) {
                if (rightExpression instanceof ListExpression) {
                    if (LIST_TYPE.equals(leftRedirect)
                            || ITERABLE_TYPE.equals(leftRedirect)
                            || Collection_TYPE.equals(leftRedirect)
                            || ArrayList_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
                        return getLiteralResultType(left, right, ArrayList_TYPE); // GROOVY-7128
                    }
                    if (SET_TYPE.equals(leftRedirect)
                            || LinkedHashSet_TYPE.isDerivedFrom(leftRedirect)) { // GROOVY-6912
                        return getLiteralResultType(left, right, LinkedHashSet_TYPE); // GROOVY-7128
                    }
                } else if (rightExpression instanceof MapExpression) {
                    if (MAP_TYPE.equals(leftRedirect)
                            || LinkedHashMap_TYPE.isDerivedFrom(leftRedirect)) {
                        return getLiteralResultType(left, right, LinkedHashMap_TYPE); // GROOVY-7128, GROOVY-9844
                    }
                } else if (rightExpression instanceof ClosureExpression
                        || rightExpression instanceof MethodPointerExpression) {
                    if (isSAMType(leftRedirect)) {
                        return left; // coercion
                    }
                }
            }

            return right;
        }

        if (isBoolIntrinsicOp(op)) {
            return boolean_TYPE;
        }

        if (op == FIND_REGEX) {
            return Matcher_TYPE;
        }

        if (isArrayOp(op)) {
            if (isOrImplements(left, MAP_TYPE) && (isStringType(right) || isGStringOrGStringStringLUB(right))) { // GROOVY-5700, GROOVY-6668, GROOVY-8212, GROOVY-8788
                PropertyExpression prop = propX(leftExpression, rightExpression); // m['xx'] -> m.xx
                return existsProperty(prop, !typeCheckingContext.isTargetOfEnclosingAssignment(expr))
                            ? getType(prop) : getTypeForMapPropertyExpression(left, prop);
            }
            Expression copy = binX(leftExpression, expr.getOperation(), rightExpression);
            copy.setSourcePosition(expr); // do not propagate BINARY_EXP_TARGET, etc.
            MethodNode method = findMethodOrFail(copy, left, "getAt", rightRedirect);
            if (method != null && !isNumberCategory(getWrapper(rightRedirect))) {
                return inferReturnTypeGenerics(left, method, rightExpression);
            }
            return inferComponentType(left, right);
        }

        String operationName = getOperationName(op);
        if (operationName == null) throw new GroovyBugError(
                "Unknown result type for binary operator " + op);
        // the left operand is determining the result of the operation
        // for primitives and their wrapper we use a fixed table here:
        ClassNode mathResultType = getMathResultType(op, leftRedirect, rightRedirect, operationName);
        if (mathResultType != null) {
            return mathResultType;
        }
        // GROOVY-9006: compare to null for types that overload equals
        if ("equals".equals(operationName) && (left == UNKNOWN_PARAMETER_TYPE
                                            || right == UNKNOWN_PARAMETER_TYPE)) {
            return boolean_TYPE;
        }
        // GROOVY-5890: do not mix Class<Type> with Type
        if (leftExpression instanceof ClassExpression) {
            left = CLASS_Type.getPlainNodeReference();
        }
        MethodNode method = findMethodOrFail(expr, left, operationName, right);
        if (method != null) {
            if (op == COMPARE_NOT_IN && isDefaultExtension(method)) {
                // GROOVY-10915: check if left implements its own isCase method
                MethodNode isCase = findMethodOrFail(expr, left, "isCase", right);
                if (isCase != null && !isDefaultExtension(isCase)) return null; // require dynamic dispatch
            }

            storeTargetMethod(expr, method);
            typeCheckMethodsWithGenericsOrFail(left, new ClassNode[]{right}, method, expr);

            if (isAssignment(op)) return left;
            if (!"compareTo".equals(operationName))
                return inferReturnTypeGenerics(left, method, args(rightExpression));
        }

        if (isCompareToBoolean(op)) return boolean_TYPE;
        if (op == COMPARE_TO) return int_TYPE;
        return null;
    }