From 9f2ce3c5214eede47de283e36671d90a46c9251e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 6 Mar 2017 12:09:46 +0300 Subject: [PATCH] Refactor synthesized invokes creation in resolution Instead of verifying that the container of an 'invoke' is a FunctionClassDescriptor instance, make sure that it's a function class checking its FQ name instead (classId + isBuiltinFunctionClass calls). This makes sure that we will create synthesized invokes in a setting where function classes are not FunctionClassDescriptor instances synthesized by the compiler, but ordinary classes from sources or binaries as well, as is going to be the case in kotlin-native --- .../resolve/calls/tasks/synthesizedInvokes.kt | 29 +++++++++++-------- .../resolve/calls/tower/InvokeProcessors.kt | 4 ++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt index c75079694cb..671ca36fcba 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt @@ -16,35 +16,40 @@ package org.jetbrains.kotlin.resolve.calls.tasks -import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor -import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor.Kind.Function -import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor.Kind.SuspendFunction -import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor +import org.jetbrains.kotlin.builtins.getFunctionalClassKind +import org.jetbrains.kotlin.builtins.isBuiltinFunctionClass import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.setSingleOverridden import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.* -private val BUILTIN_FUNCTIONS = setOf(Function, SuspendFunction) - +// Creates a descriptor denoting an extension function for a collection of non-extension "invoke"s from function types. +// For example, `fun invoke(param: P): R` becomes `fun P.invoke(): R` fun createSynthesizedInvokes(functions: Collection): Collection { val result = ArrayList(1) for (invoke in functions) { - if (invoke !is FunctionInvokeDescriptor || invoke.getValueParameters().isEmpty()) continue + if (invoke.name != OperatorNameConventions.INVOKE) continue - val synthesized = if ((invoke.getContainingDeclaration() as? FunctionClassDescriptor)?.functionKind in BUILTIN_FUNCTIONS) { + // "invoke" must have at least one parameter, which will become the receiver parameter of the synthesized "invoke" + if (invoke.valueParameters.isEmpty()) continue + + val containerClassId = (invoke.containingDeclaration as ClassDescriptor).classId + val synthesized = if (containerClassId != null && isBuiltinFunctionClass(containerClassId)) { createSynthesizedFunctionWithFirstParameterAsReceiver(invoke) } else { - val invokeDeclaration = invoke.getOverriddenDescriptors().single() + val invokeDeclaration = invoke.overriddenDescriptors.singleOrNull() + ?: error("No single overridden invoke for $invoke: ${invoke.overriddenDescriptors}") val synthesizedSuperFun = createSynthesizedFunctionWithFirstParameterAsReceiver(invokeDeclaration) val fakeOverride = synthesizedSuperFun.copy( - invoke.getContainingDeclaration(), + invoke.containingDeclaration, synthesizedSuperFun.modality, synthesizedSuperFun.visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, @@ -54,7 +59,7 @@ fun createSynthesizedInvokes(functions: Collection): Collect fakeOverride } - result.add(synthesized.substitute(TypeSubstitutor.create(invoke.getDispatchReceiverParameter()!!.type)) ?: continue) + result.add(synthesized.substitute(TypeSubstitutor.create(invoke.dispatchReceiverParameter!!.type)) ?: continue) } return result @@ -80,5 +85,5 @@ fun isSynthesizedInvoke(descriptor: DeclarationDescriptor): Boolean { } return real.kind == CallableMemberDescriptor.Kind.SYNTHESIZED && - real.containingDeclaration is FunctionClassDescriptor + real.containingDeclaration.getFunctionalClassKind() != null } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt index 1b86ef910a1..f9af73f9941 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/InvokeProcessors.kt @@ -150,7 +150,9 @@ private fun ImplicitScopeTower.getExtensionInvokeCandidateDescriptor( if (!type.isBuiltinExtensionFunctionalType) return null // todo: missing smart cast? val invokeDescriptor = type.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, location).single() - val synthesizedInvoke = createSynthesizedInvokes(listOf(invokeDescriptor)).single() + val synthesizedInvokes = createSynthesizedInvokes(listOf(invokeDescriptor)) + val synthesizedInvoke = synthesizedInvokes.singleOrNull() + ?: error("No single synthesized invoke for $invokeDescriptor: $synthesizedInvokes") // here we don't add SynthesizedDescriptor diagnostic because it should has priority as member return CandidateWithBoundDispatchReceiverImpl(extensionFunctionReceiver, synthesizedInvoke, listOf())