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
This commit is contained in:
Alexander Udalov
2017-03-06 12:09:46 +03:00
parent d188de3086
commit 9f2ce3c521
2 changed files with 20 additions and 13 deletions
@@ -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<FunctionDescriptor>): Collection<FunctionDescriptor> {
val result = ArrayList<FunctionDescriptor>(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<FunctionDescriptor>): 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
}
@@ -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())