[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
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResol
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.UnwrappedType
import java.lang.UnsupportedOperationException
@@ -39,8 +40,8 @@ class KotlinCallResolver(
resolutionCallbacks: KotlinResolutionCallbacks,
kotlinCall: KotlinCall,
expectedType: UnwrappedType?,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>,
collectAllCandidates: Boolean
collectAllCandidates: Boolean,
createFactoryProviderForInvoke: () -> CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>
): CallResolutionResult {
kotlinCall.checkCallInvariants()
@@ -54,10 +55,20 @@ class KotlinCallResolver(
scopeTower,
kotlinCall.name,
candidateFactory,
factoryProviderForInvoke,
createFactoryProviderForInvoke(),
kotlinCall.explicitReceiver?.receiver
)
}
KotlinCallKind.INVOKE -> {
createProcessorWithReceiverValueOrEmpty(kotlinCall.explicitReceiver?.receiver) {
createCallTowerProcessorForExplicitInvoke(
scopeTower,
candidateFactory,
kotlinCall.dispatchReceiverForInvokeExtension?.receiver as ReceiverValueWithSmartCastInfo,
it
)
}
}
KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException()
}
@@ -205,7 +205,11 @@ internal object CheckExplicitReceiverKindConsistency : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
when (resolvedCall.explicitReceiverKind) {
NO_EXPLICIT_RECEIVER -> if (kotlinCall.explicitReceiver is SimpleKotlinCallArgument || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError()
DISPATCH_RECEIVER, EXTENSION_RECEIVER -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError()
DISPATCH_RECEIVER, EXTENSION_RECEIVER ->
if (kotlinCall.callKind == KotlinCallKind.INVOKE && kotlinCall.dispatchReceiverForInvokeExtension == null ||
kotlinCall.callKind != KotlinCallKind.INVOKE &&
(kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension != null)
) hasError()
BOTH_RECEIVERS -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension == null) hasError()
}
}
@@ -16,10 +16,8 @@
package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.prepareReceiverRegardingCaptureTypes
@@ -43,27 +43,32 @@ fun KotlinCall.checkCallInvariants() {
explicitReceiver.safeAs<SimpleKotlinCallArgument>()?.checkReceiverInvariants()
dispatchReceiverForInvokeExtension.safeAs<SimpleKotlinCallArgument>()?.checkReceiverInvariants()
if (callKind != KotlinCallKind.FUNCTION) {
assert(externalArgument == null) {
"External argument is not allowed not for function call: $externalArgument."
}
assert(argumentsInParenthesis.isEmpty()) {
"Arguments in parenthesis should be empty for not function call: $this "
}
assert(dispatchReceiverForInvokeExtension == null) {
"Dispatch receiver for invoke should be null for not function call: $dispatchReceiverForInvokeExtension"
}
} else {
assert(externalArgument == null || !externalArgument!!.isSpread) {
"External argument cannot nave spread element: $externalArgument"
when (callKind) {
KotlinCallKind.FUNCTION, KotlinCallKind.INVOKE -> {
assert(externalArgument == null || !externalArgument!!.isSpread) {
"External argument cannot nave spread element: $externalArgument"
}
assert(externalArgument?.argumentName == null) {
"Illegal external argument with name: $externalArgument"
}
assert(dispatchReceiverForInvokeExtension == null || !dispatchReceiverForInvokeExtension!!.isSafeCall) {
"Dispatch receiver for invoke cannot be safe: $dispatchReceiverForInvokeExtension"
}
}
assert(externalArgument?.argumentName == null) {
"Illegal external argument with name: $externalArgument"
KotlinCallKind.VARIABLE -> {
assert(externalArgument == null) {
"External argument is not allowed not for function call: $externalArgument."
}
assert(argumentsInParenthesis.isEmpty()) {
"Arguments in parenthesis should be empty for not function call: $this "
}
assert(dispatchReceiverForInvokeExtension == null) {
"Dispatch receiver for invoke should be null for not function call: $dispatchReceiverForInvokeExtension"
}
}
assert(dispatchReceiverForInvokeExtension == null || !dispatchReceiverForInvokeExtension!!.isSafeCall) {
"Dispatch receiver for invoke cannot be safe: $dispatchReceiverForInvokeExtension"
}
KotlinCallKind.UNSUPPORTED -> error("Call with UNSUPPORTED kind")
}
}
@@ -207,6 +207,7 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
CheckArguments,
CheckExternalArgument
),
INVOKE(*FUNCTION.resolutionSequence.toTypedArray()),
UNSUPPORTED();
val resolutionSequence = resolutionPart.asList()