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));
}
Aggregations