@NotNull protected JetTypeInfo visitAssignmentOperation( JetBinaryExpression 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) TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create( contextWithExpectedType.trace, "trace to resolve array set method for binary expression", expression); ExpressionTypingContext context = contextWithExpectedType .replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) .replaceBindingTrace(temporaryBindingTrace); JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetType leftType = leftInfo.getType(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); JetExpression right = expression.getRight(); JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft()); if (right == null || left == null) { temporaryBindingTrace.commit(); return JetTypeInfo.create(null, dataFlowInfo); } if (leftType == null) { dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); context.trace.report(UNRESOLVED_REFERENCE.on(operationSign)); temporaryBindingTrace.commit(); return JetTypeInfo.create(null, dataFlowInfo); } ExpressionReceiver receiver = new ExpressionReceiver(left, leftType); // 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); TemporaryBindingTrace assignmentOperationTrace = TemporaryBindingTrace.create( context.trace, "trace to check assignment operation like '+=' for", expression); OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = basic.getResolutionResultsForBinaryCall( scope, name, context.replaceBindingTrace(assignmentOperationTrace), expression, receiver); JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultType(assignmentOperationDescriptors); // Check for '+' Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get( OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType)); TemporaryBindingTrace binaryOperationTrace = TemporaryBindingTrace.create( context.trace, "trace to check binary operation like '+' for", expression); OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = basic.getResolutionResultsForBinaryCall( scope, counterpartName, context.replaceBindingTrace(binaryOperationTrace), expression, receiver); JetType binaryOperationType = OverloadResolutionResultsUtil.getResultType(binaryOperationDescriptors); JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType; if (assignmentOperationType != null && binaryOperationType != null) { OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity( assignmentOperationDescriptors, binaryOperationDescriptors); context.trace.report( ASSIGN_OPERATOR_AMBIGUITY.on( operationSign, ambiguityResolutionResults.getResultingCalls())); Collection<DeclarationDescriptor> descriptors = Sets.newHashSet(); for (ResolvedCall<? extends FunctionDescriptor> call : ambiguityResolutionResults.getResultingCalls()) { descriptors.add(call.getResultingDescriptor()); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); } else if (assignmentOperationType != null) { assignmentOperationTrace.commit(); if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) { context.trace.report( ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on( operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign)); } } else { binaryOperationTrace.commit(); context.trace.record(VARIABLE_REASSIGNMENT, expression); if (left instanceof JetArrayAccessExpression) { ExpressionTypingContext contextForResolve = context .replaceScope(scope) .replaceBindingTrace( TemporaryBindingTrace.create( contextWithExpectedType.trace, "trace to resolve array set method for assignment", expression)); basic.resolveArrayAccessSetMethod( (JetArrayAccessExpression) left, right, contextForResolve, context.trace); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); } basic.checkLValue(context.trace, expression.getLeft()); temporaryBindingTrace.commit(); return JetTypeInfo.create( checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); }
private void storeResolutionResult( @NotNull Collection<? extends DeclarationDescriptor> descriptors, @NotNull Collection<? extends DeclarationDescriptor> canBeImportedDescriptors, @NotNull JetSimpleNameExpression referenceExpression, @NotNull Collection<JetScope> possibleResolutionScopes, @NotNull BindingTrace trace, @NotNull JetScope scopeToCheckVisibility) { assert canBeImportedDescriptors.size() <= descriptors.size(); assert !possibleResolutionScopes.isEmpty(); // todo completion here needs all possible resolution scopes, if there are many JetScope resolutionScope = possibleResolutionScopes.iterator().next(); // A special case - will fill all trace information if (resolveClassNamespaceAmbiguity( canBeImportedDescriptors, referenceExpression, resolutionScope, trace, scopeToCheckVisibility)) { return; } // Simple case of no descriptors if (descriptors.isEmpty()) { trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope); trace.report(UNRESOLVED_REFERENCE.on(referenceExpression)); return; } // Decide if expression has resolved reference DeclarationDescriptor descriptor = null; if (descriptors.size() == 1) { descriptor = descriptors.iterator().next(); assert canBeImportedDescriptors.size() <= 1; } else if (canBeImportedDescriptors.size() == 1) { descriptor = canBeImportedDescriptors.iterator().next(); } if (descriptor != null) { trace.record( BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next()); trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope); if (descriptor instanceof DeclarationDescriptorWithVisibility) { checkVisibility( (DeclarationDescriptorWithVisibility) descriptor, trace, referenceExpression, scopeToCheckVisibility); } } // Check for more information and additional errors if (canBeImportedDescriptors.isEmpty()) { assert descriptors.size() >= 1; trace.report(CANNOT_BE_IMPORTED.on(referenceExpression, descriptors.iterator().next())); return; } if (canBeImportedDescriptors.size() > 1) { trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors); } }
@NotNull private <D extends CallableDescriptor, F extends D> OverloadResolutionResultsImpl<F> doResolveCall( @NotNull BasicCallResolutionContext context, @NotNull List<ResolutionTask<D, F>> prioritizedTasks, // high to low priority @NotNull CallTransformer<D, F> callTransformer, @NotNull JetReferenceExpression reference) { ResolutionDebugInfo.Data debugInfo = ResolutionDebugInfo.create(); context.trace.record( ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement(), debugInfo); context.trace.record(RESOLUTION_SCOPE, context.call.getCalleeExpression(), context.scope); if (context.dataFlowInfo.hasTypeInfoConstraints()) { context.trace.record( NON_DEFAULT_EXPRESSION_DATA_FLOW, context.call.getCalleeExpression(), context.dataFlowInfo); } debugInfo.set(ResolutionDebugInfo.TASKS, prioritizedTasks); if (context.checkArguments == CheckValueArgumentsMode.ENABLED) { argumentTypeResolver.analyzeArgumentsAndRecordTypes(context); } TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null; OverloadResolutionResultsImpl<F> resultsForFirstNonemptyCandidateSet = null; for (ResolutionTask<D, F> task : prioritizedTasks) { TemporaryBindingTrace taskTrace = TemporaryBindingTrace.create( context.trace, "trace to resolve a task for", task.reference); OverloadResolutionResultsImpl<F> results = performResolutionGuardedForExtraFunctionLiteralArguments( task.replaceBindingTrace(taskTrace), callTransformer); if (results.isSuccess() || results.isAmbiguity()) { taskTrace.commit(); if (results.isSuccess()) { debugInfo.set(ResolutionDebugInfo.RESULT, results.getResultingCall()); } resolveFunctionArguments(context, results); return results; } if (results.getResultCode() == INCOMPLETE_TYPE_INFERENCE) { results.setTrace(taskTrace); return results; } boolean updateResults = traceForFirstNonemptyCandidateSet == null || (resultsForFirstNonemptyCandidateSet.getResultCode() == CANDIDATES_WITH_WRONG_RECEIVER && results.getResultCode() != CANDIDATES_WITH_WRONG_RECEIVER); if (!task.getCandidates().isEmpty() && !results.isNothing() && updateResults) { traceForFirstNonemptyCandidateSet = taskTrace; resultsForFirstNonemptyCandidateSet = results; } } if (traceForFirstNonemptyCandidateSet != null) { traceForFirstNonemptyCandidateSet.commit(); if (resultsForFirstNonemptyCandidateSet.isSingleResult()) { debugInfo.set( ResolutionDebugInfo.RESULT, resultsForFirstNonemptyCandidateSet.getResultingCall()); } resolveFunctionArguments(context, resultsForFirstNonemptyCandidateSet); } else { context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference)); argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS); } return resultsForFirstNonemptyCandidateSet != null ? resultsForFirstNonemptyCandidateSet : OverloadResolutionResultsImpl.<F>nameNotFound(); }