[NI] Support implicit invoke calls on parenthesized receivers

This commit is contained in:
Mikhail Zarechenskiy
2018-04-20 08:12:31 +03:00
parent 1e7682afc0
commit 397cc4f772
22 changed files with 211 additions and 64 deletions
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.CallTransformer
import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isBinaryRemOperator
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
@@ -66,7 +67,8 @@ class PSICallResolver(
val defaultResolutionKinds = setOf(
NewResolutionOldInference.ResolutionKind.Function,
NewResolutionOldInference.ResolutionKind.Variable
NewResolutionOldInference.ResolutionKind.Variable,
NewResolutionOldInference.ResolutionKind.Invoke
)
fun <D : CallableDescriptor> runResolutionAndInference(
@@ -78,23 +80,23 @@ class PSICallResolver(
val isBinaryRemOperator = isBinaryRemOperator(context.call)
val refinedName = refineNameForRemOperator(isBinaryRemOperator, name)
val kotlinCall = toKotlinCall(context, resolutionKind.toKotlinCallKind(), context.call, refinedName, tracingStrategy)
val kotlinCallKind = resolutionKind.toKotlinCallKind()
val kotlinCall = toKotlinCall(context, kotlinCallKind, context.call, refinedName, tracingStrategy)
val scopeTower = ASTScopeTower(context)
val resolutionCallbacks = createResolutionCallbacks(context)
val factoryProviderForInvoke = FactoryProviderForInvoke(context, scopeTower, kotlinCall)
val expectedType = calculateExpectedType(context)
var result = kotlinCallResolver.resolveCall(
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates
)
var result =
kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, context.collectAllCandidates) {
FactoryProviderForInvoke(context, scopeTower, kotlinCall)
}
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, scopeTower, resolutionCallbacks, expectedType)
result = resolveToDeprecatedMod(name, context, kotlinCallKind, tracingStrategy, scopeTower, resolutionCallbacks, expectedType)
}
if (result.isEmpty() && reportAdditionalDiagnosticIfNoCandidates(context, scopeTower, resolutionKind, kotlinCall)) {
if (result.isEmpty() && reportAdditionalDiagnosticIfNoCandidates(context, scopeTower, kotlinCallKind, kotlinCall)) {
return OverloadResolutionResultsImpl.nameNotFound()
}
@@ -126,25 +128,24 @@ class PSICallResolver(
scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates
)
return convertToOverloadResolutionResults(context, result, tracingStrategy)
}
private fun resolveToDeprecatedMod(
remOperatorName: Name,
context: BasicCallResolutionContext,
resolutionKind: NewResolutionOldInference.ResolutionKind,
kotlinCallKind: KotlinCallKind,
tracingStrategy: TracingStrategy,
scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacksImpl,
expectedType: UnwrappedType?
): CallResolutionResult {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.toKotlinCallKind(), context.call, deprecatedName, tracingStrategy)
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
val callWithDeprecatedName = toKotlinCall(context, kotlinCallKind, context.call, deprecatedName, tracingStrategy)
return kotlinCallResolver.resolveCall(
scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
refinedProviderForInvokeFactory, context.collectAllCandidates
)
scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, context.collectAllCandidates
) {
FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
}
}
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
@@ -303,7 +304,7 @@ class PSICallResolver(
private fun reportAdditionalDiagnosticIfNoCandidates(
context: BasicCallResolutionContext,
scopeTower: ImplicitScopeTower,
kind: NewResolutionOldInference.ResolutionKind,
kind: KotlinCallKind,
kotlinCall: KotlinCall
): Boolean {
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
@@ -451,15 +452,14 @@ class PSICallResolver(
}
}
private fun NewResolutionOldInference.ResolutionKind.toKotlinCallKind(): KotlinCallKind {
return when (this) {
private fun NewResolutionOldInference.ResolutionKind.toKotlinCallKind(): KotlinCallKind =
when (this) {
is NewResolutionOldInference.ResolutionKind.Function -> KotlinCallKind.FUNCTION
is NewResolutionOldInference.ResolutionKind.Variable -> KotlinCallKind.VARIABLE
is NewResolutionOldInference.ResolutionKind.Invoke -> KotlinCallKind.UNSUPPORTED
is NewResolutionOldInference.ResolutionKind.Invoke -> KotlinCallKind.INVOKE
is NewResolutionOldInference.ResolutionKind.CallableReference -> KotlinCallKind.UNSUPPORTED
is NewResolutionOldInference.ResolutionKind.GivenCandidates -> KotlinCallKind.UNSUPPORTED
}
}
private fun toKotlinCall(
context: BasicCallResolutionContext,
@@ -469,8 +469,11 @@ class PSICallResolver(
tracingStrategy: TracingStrategy,
forcedExplicitReceiver: Receiver? = null
): PSIKotlinCallImpl {
val resolvedExplicitReceiver =
resolveExplicitReceiver(context, forcedExplicitReceiver ?: oldCall.explicitReceiver, oldCall.isSafeCall())
val resolvedExplicitReceiver = resolveReceiver(
context, forcedExplicitReceiver ?: oldCall.explicitReceiver, oldCall.isSafeCall(), isVariableReceiverForInvoke = false
)
val dispatchReceiverForInvoke = resolveDispatchReceiverForInvoke(context, kotlinCallKind, oldCall)
val resolvedTypeArguments = resolveTypeArguments(context, oldCall.typeArguments)
val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
@@ -510,15 +513,30 @@ class PSICallResolver(
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
return PSIKotlinCallImpl(
kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments,
resolvedArgumentsInParenthesis, astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments
kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, dispatchReceiverForInvoke, name,
resolvedTypeArguments, resolvedArgumentsInParenthesis, astExternalArgument, context.dataFlowInfo, resultDataFlowInfo,
context.dataFlowInfoForArguments
)
}
private fun resolveExplicitReceiver(
private fun resolveDispatchReceiverForInvoke(
context: BasicCallResolutionContext,
kotlinCallKind: KotlinCallKind,
oldCall: Call
): ReceiverKotlinCallArgument? {
if (kotlinCallKind != KotlinCallKind.INVOKE) return null
require(oldCall is CallTransformer.CallForImplicitInvoke) { "Call should be CallForImplicitInvoke, but it is: $oldCall" }
val dispatchReceiver = oldCall.dispatchReceiver!! // dispatch receiver from CallForImplicitInvoke is always not null
return resolveReceiver(context, dispatchReceiver, isSafeCall = false, isVariableReceiverForInvoke = true)
}
private fun resolveReceiver(
context: BasicCallResolutionContext,
oldReceiver: Receiver?,
isSafeCall: Boolean
isSafeCall: Boolean,
isVariableReceiverForInvoke: Boolean
): ReceiverKotlinCallArgument? =
when (oldReceiver) {
null -> null
@@ -546,7 +564,7 @@ class PSICallResolver(
}
}
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall, isVariableReceiverForInvoke)
}
else -> error("Incorrect receiver: $oldReceiver")
}
@@ -50,6 +50,7 @@ class PSIKotlinCallImpl(
override val psiCall: Call,
override val tracingStrategy: TracingStrategy,
override val explicitReceiver: ReceiverKotlinCallArgument?,
override val dispatchReceiverForInvokeExtension: ReceiverKotlinCallArgument?,
override val name: Name,
override val typeArguments: List<TypeArgument>,
override val argumentsInParenthesis: List<KotlinCallArgument>,