From 12a6461006eca5f5d0c107e5b3e5e220c1bddc52 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 26 May 2015 17:34:43 +0300 Subject: [PATCH] Report 'free function called as extension' on Function subclasses You can't make a value of some type invokable as an extension by adding 'extension' annotation to the type --- .../resolve/calls/tasks/synthesizedInvokes.kt | 13 ++++++++++--- .../tests/FreeFunctionCalledAsExtension.kt | 10 ++++++++++ .../tests/FreeFunctionCalledAsExtension.txt | 8 ++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt index b843b1d9acb..9a33c481df4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/synthesizedInvokes.kt @@ -87,7 +87,14 @@ private fun createSynthesizedFunctionWithFirstParameterAsReceiver(descriptor: Fu } fun isSynthesizedInvoke(descriptor: DeclarationDescriptor): Boolean { - return descriptor.getName() == OperatorConventions.INVOKE && - (descriptor as? FunctionDescriptor)?.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED && - descriptor.getContainingDeclaration() is FunctionClassDescriptor + if (descriptor.getName() != OperatorConventions.INVOKE || descriptor !is FunctionDescriptor) return false + + var real: FunctionDescriptor = descriptor + while (!real.getKind().isReal()) { + // You can't override two different synthesized invokes at the same time + real = real.getOverriddenDescriptors().singleOrNull() ?: return false + } + + return real.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED && + real.getContainingDeclaration() is FunctionClassDescriptor } diff --git a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt index c465e3df5ae..0b552e64264 100644 --- a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt +++ b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt @@ -1,3 +1,13 @@ fun foo(a: (String) -> Unit) { "".a() } + + + +interface A : (String) -> Unit {} + +fun foo(a: @extension A) { + // @extension annotation on an unrelated type shouldn't have any effect on this diagnostic. + // Only kotlin.Function{n} type annotated with @extension should + "".a() +} diff --git a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt index 6a88805579a..f6d7797c85a 100644 --- a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt +++ b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt @@ -1,3 +1,11 @@ package internal fun foo(/*0*/ a: (kotlin.String) -> kotlin.Unit): kotlin.Unit +internal fun foo(/*0*/ a: @[kotlin.extension()] A): kotlin.Unit + +internal interface A : (kotlin.String) -> kotlin.Unit { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun invoke(/*0*/ p1: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +}