Report error when free function is called as extension
This commit is contained in:
@@ -411,6 +411,8 @@ public interface Errors {
|
|||||||
DiagnosticFactory1<JetExpression, JetType> MISSING_RECEIVER = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<JetExpression, JetType> MISSING_RECEIVER = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory0<JetExpression> NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<JetExpression> NO_RECEIVER_ALLOWED = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
|
DiagnosticFactory0<JetExpression> FREE_FUNCTION_CALLED_AS_EXTENSION = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
// Call resolution
|
// Call resolution
|
||||||
|
|
||||||
DiagnosticFactory1<JetExpression, String> ILLEGAL_SELECTOR = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<JetExpression, String> ILLEGAL_SELECTOR = DiagnosticFactory1.create(ERROR);
|
||||||
|
|||||||
+2
@@ -546,6 +546,8 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(MISSING_RECEIVER, "A receiver of type {0} is required", RENDER_TYPE);
|
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(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(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);
|
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.DataFlowValueFactory;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils;
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTask;
|
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.calls.util.FakeCallableDescriptorForObject;
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
@@ -169,6 +170,8 @@ public class CandidateResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkAbstractAndSuper(context);
|
checkAbstractAndSuper(context);
|
||||||
|
|
||||||
|
checkNonExtensionCalledWithReceiver(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkDispatchReceiver(@NotNull CallCandidateResolutionContext<?> 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
|
@Nullable
|
||||||
private static JetSuperExpression getReceiverSuper(@NotNull ReceiverValue receiver) {
|
private static JetSuperExpression getReceiverSuper(@NotNull ReceiverValue receiver) {
|
||||||
if (receiver instanceof ExpressionReceiver) {
|
if (receiver instanceof ExpressionReceiver) {
|
||||||
|
|||||||
+4
@@ -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
|
@Override
|
||||||
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
|
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void freeFunctionCalledAsExtension(@NotNull BindingTrace trace) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
void bindCall(@NotNull BindingTrace trace, @NotNull Call call);
|
void bindCall(@NotNull BindingTrace trace, @NotNull Call call);
|
||||||
@@ -149,4 +152,6 @@ public interface TracingStrategy {
|
|||||||
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
|
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
|
||||||
|
|
||||||
void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData);
|
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.FunctionClassDescriptor.Kind.Function
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
fun createSynthesizedInvokes(functions: Collection<FunctionDescriptor>): Collection<FunctionDescriptor> {
|
fun createSynthesizedInvokes(functions: Collection<FunctionDescriptor>): Collection<FunctionDescriptor> {
|
||||||
@@ -83,3 +85,9 @@ private fun createSynthesizedFunctionWithFirstParameterAsReceiver(descriptor: Fu
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isSynthesizedInvoke(descriptor: DeclarationDescriptor): Boolean {
|
||||||
|
return descriptor.getName() == OperatorConventions.INVOKE &&
|
||||||
|
(descriptor as? FunctionDescriptor)?.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED &&
|
||||||
|
descriptor.getContainingDeclaration() is FunctionClassDescriptor
|
||||||
|
}
|
||||||
|
|||||||
+5
@@ -521,5 +521,10 @@ public class ControlStructureTypingUtils {
|
|||||||
) {
|
) {
|
||||||
logError();
|
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
|
||||||
+2
-2
@@ -5,7 +5,7 @@ fun test1(f: String.() -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test2(f: (Int) -> Int) {
|
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);
|
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")
|
@TestMetadata("FunctionCalleeExpressions.kt")
|
||||||
public void testFunctionCalleeExpressions() throws Exception {
|
public void testFunctionCalleeExpressions() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/FunctionCalleeExpressions.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user