diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 6f6a0af5915..81621e23baa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.TypeResolver import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver +import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny @@ -59,11 +61,8 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.expressions.* import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ControlStructureDataFlowInfo -import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver -import org.jetbrains.kotlin.types.expressions.DoubleColonLHS -import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext -import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import java.util.* @@ -93,14 +92,24 @@ class PSICallResolver( resolutionKind: NewResolutionOldInference.ResolutionKind, tracingStrategy: TracingStrategy ) : OverloadResolutionResults { - val kotlinCall = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, name, tracingStrategy) + val isBinaryRemOperator = isBinaryRemOperator(context.call) + val refinedName = refineNameForRemOperator(isBinaryRemOperator, name) + + val kotlinCall = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, refinedName, tracingStrategy) val scopeTower = ASTScopeTower(context) val lambdaAnalyzer = createLambdaAnalyzer(context) val callContext = createCallContext(scopeTower, lambdaAnalyzer) val factoryProviderForInvoke = FactoryProviderForInvoke(context, callContext, kotlinCall) - val result = kotlinCallResolver.resolveCall(callContext, kotlinCall, calculateExpectedType(context), factoryProviderForInvoke) + val expectedType = calculateExpectedType(context) + var result = kotlinCallResolver.resolveCall(callContext, kotlinCall, expectedType, factoryProviderForInvoke) + + val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) + if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllCompletedAndInapplicable())) { + result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, callContext, expectedType) + } + if (result.isEmpty() && reportAdditionalDiagnosticIfNoCandidates(context, scopeTower, resolutionKind.kotlinCallKind, kotlinCall)) { return OverloadResolutionResultsImpl.nameNotFound() } @@ -132,6 +141,24 @@ class PSICallResolver( } + private fun resolveToDeprecatedMod( + remOperatorName: Name, + context: BasicCallResolutionContext, + resolutionKind: NewResolutionOldInference.ResolutionKind, + tracingStrategy: TracingStrategy, callContext: KotlinCallContext, + expectedType: UnwrappedType? + ): Collection { + val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! + val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy) + val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, callContext, callWithDeprecatedName) + return kotlinCallResolver.resolveCall(callContext, callWithDeprecatedName, expectedType, refinedProviderForInvokeFactory) + } + + private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name { + val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) + return if (isBinaryRemOperator && !shouldUseOperatorRem) OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]!! else name + } + private fun createLambdaAnalyzer(context: BasicCallResolutionContext) = KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, kotlinToResolvedCallTransformer, argumentTypeResolver, doubleColonExpressionResolver) @@ -195,6 +222,17 @@ class PSICallResolver( !it.completedCall.resolutionStatus.resultingApplicability.isSuccess } + private fun Collection.areAllCompletedAndInapplicable() = + all { + val applicability = when (it) { + is ResolvedKotlinCall.CompletedResolvedKotlinCall -> + it.completedCall.resolutionStatus.resultingApplicability + is ResolvedKotlinCall.OnlyResolvedKotlinCall -> + it.candidate.status.resultingApplicability + } + applicability == ResolutionCandidateApplicability.INAPPLICABLE || applicability == ResolutionCandidateApplicability.HIDDEN + } + // true if we found something private fun reportAdditionalDiagnosticIfNoCandidates( context: BasicCallResolutionContext,