Report error when free function is called as extension

This commit is contained in:
Alexander Udalov
2015-05-25 20:10:46 +03:00
parent 14c2690447
commit ea6d0b464d
11 changed files with 53 additions and 2 deletions
@@ -411,6 +411,8 @@ public interface Errors {
DiagnosticFactory1<JetExpression, JetType> MISSING_RECEIVER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<JetExpression> NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetExpression> FREE_FUNCTION_CALLED_AS_EXTENSION = DiagnosticFactory0.create(ERROR);
// Call resolution
DiagnosticFactory1<JetExpression, String> ILLEGAL_SELECTOR = DiagnosticFactory1.create(ERROR);
@@ -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);
@@ -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) {
@@ -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));
}
}
@@ -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);
}
@@ -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<FunctionDescriptor>): Collection<FunctionDescriptor> {
@@ -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
}
@@ -521,5 +521,10 @@ public class ControlStructureTypingUtils {
) {
logError();
}
@Override
public void freeFunctionCalledAsExtension(@NotNull BindingTrace trace) {
logError();
}
}
}
@@ -0,0 +1,3 @@
fun foo(a: (String) -> Unit) {
"".<!FREE_FUNCTION_CALLED_AS_EXTENSION!>a<!>()
}
@@ -0,0 +1,3 @@
package
internal fun foo(/*0*/ a: (kotlin.String) -> kotlin.Unit): kotlin.Unit
@@ -5,7 +5,7 @@ fun test1(f: String.() -> Unit) {
}
fun test2(f: (Int) -> Int) {
1.f(<!TOO_MANY_ARGUMENTS!>2<!>)
1.<!FREE_FUNCTION_CALLED_AS_EXTENSION!>f<!>(<!TOO_MANY_ARGUMENTS!>2<!>)
2.(f)(<!TOO_MANY_ARGUMENTS!>2<!>)
2.<!FREE_FUNCTION_CALLED_AS_EXTENSION!>(f)<!>(<!TOO_MANY_ARGUMENTS!>2<!>)
}
@@ -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");