From ea6d0b464d280a80b123d1905b5e9d39e6403c23 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 25 May 2015 20:10:46 +0300 Subject: [PATCH] Report error when free function is called as extension --- .../org/jetbrains/kotlin/diagnostics/Errors.java | 2 ++ .../diagnostics/rendering/DefaultErrorMessages.java | 2 ++ .../kotlin/resolve/calls/CandidateResolver.java | 13 +++++++++++++ .../calls/tasks/AbstractTracingStrategy.java | 4 ++++ .../kotlin/resolve/calls/tasks/TracingStrategy.java | 5 +++++ .../resolve/calls/tasks/synthesizedInvokes.kt | 8 ++++++++ .../expressions/ControlStructureTypingUtils.java | 5 +++++ .../tests/FreeFunctionCalledAsExtension.kt | 3 +++ .../tests/FreeFunctionCalledAsExtension.txt | 3 +++ .../invoke/errors/receiverPresenceErrorForInvoke.kt | 4 ++-- .../checkers/JetDiagnosticsTestGenerated.java | 6 ++++++ 11 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt create mode 100644 compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index a49696f3842..2d1e6e5b875 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -411,6 +411,8 @@ public interface Errors { DiagnosticFactory1 MISSING_RECEIVER = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 FREE_FUNCTION_CALLED_AS_EXTENSION = DiagnosticFactory0.create(ERROR); + // Call resolution DiagnosticFactory1 ILLEGAL_SELECTOR = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 8ce8aa17842..ac6b36a3d86 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -546,6 +546,8 @@ public class DefaultErrorMessages { MAP.put(MISSING_RECEIVER, "A receiver of type {0} is required", RENDER_TYPE); MAP.put(NO_RECEIVER_ALLOWED, "No receiver can be passed to this function or property"); + MAP.put(FREE_FUNCTION_CALLED_AS_EXTENSION, "The function cannot be called as an extension function"); + MAP.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class"); MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "Type inference failed: {0}", TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java index 90c2af91d0e..f533b0c7271 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory; import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils; import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTask; +import org.jetbrains.kotlin.resolve.calls.tasks.TasksPackage; import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; @@ -169,6 +170,8 @@ public class CandidateResolver { } checkAbstractAndSuper(context); + + checkNonExtensionCalledWithReceiver(context); } private static boolean checkDispatchReceiver(@NotNull CallCandidateResolutionContext context) { @@ -238,6 +241,16 @@ public class CandidateResolver { } } + private static void checkNonExtensionCalledWithReceiver(@NotNull CallCandidateResolutionContext context) { + MutableResolvedCall candidateCall = context.candidateCall; + + if (TasksPackage.isSynthesizedInvoke(candidateCall.getCandidateDescriptor()) && + !KotlinBuiltIns.isExtensionFunctionType(candidateCall.getDispatchReceiver().getType())) { + context.tracing.freeFunctionCalledAsExtension(context.trace); + candidateCall.addStatus(OTHER_ERROR); + } + } + @Nullable private static JetSuperExpression getReceiverSuper(@NotNull ReceiverValue receiver) { if (receiver instanceof ExpressionReceiver) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java index cd809089781..a3f1ceaf1f6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java @@ -239,4 +239,8 @@ public abstract class AbstractTracingStrategy implements TracingStrategy { } } + @Override + public void freeFunctionCalledAsExtension(@NotNull BindingTrace trace) { + trace.report(FREE_FUNCTION_CALLED_AS_EXTENSION.on(reference)); + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java index 751549e920b..f8a5c883b1c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TracingStrategy.java @@ -99,6 +99,9 @@ public interface TracingStrategy { @Override public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {} + + @Override + public void freeFunctionCalledAsExtension(@NotNull BindingTrace trace) { } }; void bindCall(@NotNull BindingTrace trace, @NotNull Call call); @@ -149,4 +152,6 @@ public interface TracingStrategy { void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor); void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData); + + void freeFunctionCalledAsExtension(@NotNull BindingTrace trace); } 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 467ca46916d..b843b1d9acb 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 @@ -20,11 +20,13 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor.Kind.Function import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.expressions.OperatorConventions import java.util.ArrayList fun createSynthesizedInvokes(functions: Collection): Collection { @@ -83,3 +85,9 @@ private fun createSynthesizedFunctionWithFirstParameterAsReceiver(descriptor: Fu return result } + +fun isSynthesizedInvoke(descriptor: DeclarationDescriptor): Boolean { + return descriptor.getName() == OperatorConventions.INVOKE && + (descriptor as? FunctionDescriptor)?.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED && + descriptor.getContainingDeclaration() is FunctionClassDescriptor +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java index b48bc668227..e43450bcbb4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java @@ -521,5 +521,10 @@ public class ControlStructureTypingUtils { ) { logError(); } + + @Override + public void freeFunctionCalledAsExtension(@NotNull BindingTrace trace) { + logError(); + } } } diff --git a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt new file mode 100644 index 00000000000..c465e3df5ae --- /dev/null +++ b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt @@ -0,0 +1,3 @@ +fun foo(a: (String) -> Unit) { + "".a() +} diff --git a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt new file mode 100644 index 00000000000..6a88805579a --- /dev/null +++ b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.txt @@ -0,0 +1,3 @@ +package + +internal fun foo(/*0*/ a: (kotlin.String) -> kotlin.Unit): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt index 230a9ce53d4..0a2521aaf5c 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.kt @@ -5,7 +5,7 @@ fun test1(f: String.() -> Unit) { } fun test2(f: (Int) -> Int) { - 1.f(2) + 1.f(2) - 2.(f)(2) + 2.(f)(2) } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 914d580e4d8..6f010c292d8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -223,6 +223,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("FreeFunctionCalledAsExtension.kt") + public void testFreeFunctionCalledAsExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt"); + doTest(fileName); + } + @TestMetadata("FunctionCalleeExpressions.kt") public void testFunctionCalleeExpressions() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt");