Search in sources :

Example 1 with TemporaryTraceAndCache

use of org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache in project kotlin by JetBrains.

the class ExpressionTypingVisitorForStatements method visitAssignmentOperation.

@NotNull
protected KotlinTypeInfo visitAssignmentOperation(KtBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) {
    //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there)
    TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create(contextWithExpectedType, "trace to resolve array set method for binary expression", expression);
    ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT);
    KtSimpleNameExpression operationSign = expression.getOperationReference();
    IElementType operationType = operationSign.getReferencedNameElementType();
    KtExpression leftOperand = expression.getLeft();
    KotlinTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(leftOperand, context, facade);
    KotlinType leftType = leftInfo.getType();
    KtExpression right = expression.getRight();
    KtExpression left = leftOperand == null ? null : deparenthesize(leftOperand);
    if (right == null || left == null) {
        temporary.commit();
        return leftInfo.clearType();
    }
    if (leftType == null) {
        KotlinTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
        context.trace.report(UNRESOLVED_REFERENCE.on(operationSign, operationSign));
        temporary.commit();
        return rightInfo.clearType();
    }
    ExpressionReceiver receiver = ExpressionReceiver.Companion.create(left, leftType, context.trace.getBindingContext());
    // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we then also assign)
    // Check for '+='
    Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
    TemporaryTraceAndCache temporaryForAssignmentOperation = TemporaryTraceAndCache.create(context, "trace to check assignment operation like '+=' for", expression);
    OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = components.callResolver.resolveBinaryCall(context.replaceTraceAndCache(temporaryForAssignmentOperation).replaceScope(scope), receiver, expression, name);
    KotlinType assignmentOperationType = OverloadResolutionResultsUtil.getResultingType(assignmentOperationDescriptors, context.contextDependency);
    OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors;
    KotlinType binaryOperationType;
    TemporaryTraceAndCache temporaryForBinaryOperation = TemporaryTraceAndCache.create(context, "trace to check binary operation like '+' for", expression);
    TemporaryBindingTrace ignoreReportsTrace = TemporaryBindingTrace.create(context.trace, "Trace for checking assignability");
    boolean lhsAssignable = basic.checkLValue(ignoreReportsTrace, context, left, right, expression);
    if (assignmentOperationType == null || lhsAssignable) {
        // Check for '+'
        Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
        binaryOperationDescriptors = components.callResolver.resolveBinaryCall(context.replaceTraceAndCache(temporaryForBinaryOperation).replaceScope(scope), receiver, expression, counterpartName);
        binaryOperationType = OverloadResolutionResultsUtil.getResultingType(binaryOperationDescriptors, context.contextDependency);
    } else {
        binaryOperationDescriptors = OverloadResolutionResultsImpl.nameNotFound();
        binaryOperationType = null;
    }
    KotlinType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType;
    KotlinTypeInfo rightInfo = leftInfo;
    boolean hasRemAssignOperation = atLeastOneOperation(assignmentOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM_ASSIGN);
    boolean hasRemBinaryOperation = atLeastOneOperation(binaryOperationDescriptors.getResultingCalls(), OperatorNameConventions.REM);
    boolean oneTypeOfModRemOperations = hasRemAssignOperation == hasRemBinaryOperation;
    if (assignmentOperationDescriptors.isSuccess() && binaryOperationDescriptors.isSuccess() && oneTypeOfModRemOperations) {
        // Both 'plus()' and 'plusAssign()' available => ambiguity
        OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors);
        context.trace.report(ASSIGN_OPERATOR_AMBIGUITY.on(operationSign, ambiguityResolutionResults.getResultingCalls()));
        Collection<DeclarationDescriptor> descriptors = Sets.newHashSet();
        for (ResolvedCall<?> resolvedCall : ambiguityResolutionResults.getResultingCalls()) {
            descriptors.add(resolvedCall.getResultingDescriptor());
        }
        rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
        context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors);
    } else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess()) && (!hasRemBinaryOperation || !binaryOperationDescriptors.isSuccess())) {
        // There's 'plusAssign()', so we do a.plusAssign(b)
        temporaryForAssignmentOperation.commit();
        if (!KotlinTypeChecker.DEFAULT.equalTypes(components.builtIns.getUnitType(), assignmentOperationType)) {
            context.trace.report(ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on(operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign));
        }
    } else {
        // There's only 'plus()', so we try 'a = a + b'
        temporaryForBinaryOperation.commit();
        context.trace.record(VARIABLE_REASSIGNMENT, expression);
        if (left instanceof KtArrayAccessExpression) {
            ExpressionTypingContext contextForResolve = context.replaceScope(scope).replaceBindingTrace(TemporaryBindingTrace.create(context.trace, "trace to resolve array set method for assignment", expression));
            basic.resolveImplicitArrayAccessSetMethod((KtArrayAccessExpression) left, right, contextForResolve, context.trace);
        }
        rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo()));
        KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType);
        components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType).replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left)));
        basic.checkLValue(context.trace, context, leftOperand, right, expression);
    }
    temporary.commit();
    return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType));
}
Also used : KotlinType(org.jetbrains.kotlin.types.KotlinType) CallPosition(org.jetbrains.kotlin.resolve.calls.context.CallPosition) Name(org.jetbrains.kotlin.name.Name) TemporaryBindingTrace(org.jetbrains.kotlin.resolve.TemporaryBindingTrace) IElementType(com.intellij.psi.tree.IElementType) ExpressionReceiver(org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver) TemporaryTraceAndCache(org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

IElementType (com.intellij.psi.tree.IElementType)1 NotNull (org.jetbrains.annotations.NotNull)1 Name (org.jetbrains.kotlin.name.Name)1 TemporaryBindingTrace (org.jetbrains.kotlin.resolve.TemporaryBindingTrace)1 CallPosition (org.jetbrains.kotlin.resolve.calls.context.CallPosition)1 TemporaryTraceAndCache (org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache)1 ExpressionReceiver (org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver)1 KotlinType (org.jetbrains.kotlin.types.KotlinType)1