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);
|
||||
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);
|
||||
|
||||
+2
@@ -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) {
|
||||
|
||||
+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
|
||||
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
|
||||
}
|
||||
|
||||
+5
@@ -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
|
||||
+2
-2
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user