[NI] Support implicit invoke calls on parenthesized receivers
This commit is contained in:
@@ -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>,
|
||||
|
||||
Reference in New Issue
Block a user