From 29fa87ee7c13e7f51e4d5f44d89bf6d1ef80c391 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Fri, 3 Oct 2014 14:55:06 +0400 Subject: [PATCH] Slightly reduce number of candidates in task prioritizer return only extensions (functions) when we expecting extensions (not all functions); for properties it's not that easy: they may have extension function types, and we want to avoid early computing of deferred types rename: getNonMembersByName -> getExtensionsByName Report NO_RECEIVER_ALLOWED for '42.(f)()' where f: () -> Unit in TracingStrategyForInvoke (we don't store candidates for such 'invoke' functions any more) --- .../jet/lang/resolve/calls/CallResolver.java | 2 +- .../lang/resolve/calls/CandidateResolver.java | 5 +---- .../tasks/CallableDescriptorCollectors.kt | 17 +++++++------- .../resolve/calls/tasks/TaskPrioritizer.java | 4 ++-- .../calls/tasks/TracingStrategyForInvoke.java | 22 +++++++++++++++++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index b1a4a8ce567..7aa79cf604e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -287,7 +287,7 @@ public class CallResolver { else if (calleeExpression != null) { // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) - JetType calleeType = expressionTypingServices.safeGetType(context.scope, calleeExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); // We are actually expecting a function, but there seems to be no easy way of expressing this + JetType calleeType = expressionTypingServices.safeGetType(context.scope, calleeExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); ExpressionReceiver expressionReceiver = new ExpressionReceiver(calleeExpression, calleeType); Call call = new CallTransformer.CallForImplicitInvoke( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index ada3a2fbc14..36b730f217f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -104,10 +104,7 @@ public class CandidateResolver { ValueArgumentsToParametersMapper.Status argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters( context.call, context.tracing, candidateCall, unmappedArguments); if (!argumentMappingStatus.isSuccess()) { - //For the expressions like '42.(f)()' where f: () -> Unit we'd like to generate an error 'no receiver admitted', - //not to throw away the candidate. - if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR - && !CallResolverUtil.isInvokeCallOnExpressionWithBothReceivers(context.call)) { + if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) { candidateCall.addStatus(RECEIVER_PRESENCE_ERROR); checkAllValueArguments(context, SHAPE_FUNCTION_ARGUMENTS); return; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/CallableDescriptorCollectors.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/CallableDescriptorCollectors.kt index 90c2eb5d749..f1c54dad7d1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/CallableDescriptorCollectors.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/CallableDescriptorCollectors.kt @@ -32,7 +32,7 @@ public trait CallableDescriptorCollector { public fun getMembersByName(receiver: JetType, name: Name, bindingTrace: BindingTrace): Collection - public fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection + public fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection } private val FUNCTIONS_COLLECTOR = FilteredCollector(FunctionCollector) @@ -66,8 +66,8 @@ private object FunctionCollector : CallableDescriptorCollector { - return scope.getFunctions(name) + override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { + return scope.getFunctions(name).filter { it.getExtensionReceiverParameter() != null } } private fun getConstructors(scope: JetScope, name: Name): Collection { @@ -106,7 +106,8 @@ private object VariableCollector : CallableDescriptorCollector { + override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { + // property may have an extension function type, we check the applicability later to avoid an early computing of deferred types return (listOf(scope.getLocalVariable(name)) + scope.getProperties(name)).filterNotNull() } @@ -125,8 +126,8 @@ private object PropertyCollector : CallableDescriptorCollector { - return filterProperties(VARIABLES_COLLECTOR.getNonMembersByName(scope, name, bindingTrace)) + override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { + return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, bindingTrace)) } override fun toString() = "PROPERTIES" @@ -142,8 +143,8 @@ private class FilteredCollector(private val delegate: Ca return filterOutMembersFromLibrarySource(delegate.getMembersByName(receiver, name, bindingTrace)) } - override fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { - return filterOutMembersFromLibrarySource(delegate.getNonMembersByName(scope, name, bindingTrace)) + override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection { + return filterOutMembersFromLibrarySource(delegate.getExtensionsByName(scope, name, bindingTrace)) } override fun toString(): String { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java index ada2aec2c4c..90faf006682 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TaskPrioritizer.java @@ -153,7 +153,7 @@ public class TaskPrioritizer { } //extensions Collection> extensions = convertWithImpliedThis( - c.scope, explicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace), + c.scope, explicitReceiver, callableDescriptorCollector.getExtensionsByName(c.scope, c.name, c.context.trace), createKind(EXTENSION_RECEIVER, isExplicit), c.context.call); c.result.addCandidates(extensions); } @@ -170,7 +170,7 @@ public class TaskPrioritizer { @NotNull CallableDescriptorCollector callableDescriptorCollector, TaskPrioritizerContext c, @NotNull ExplicitReceiverKind receiverKind ) { - Collection memberExtensions = callableDescriptorCollector.getNonMembersByName( + Collection memberExtensions = callableDescriptorCollector.getExtensionsByName( dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace); c.result.addCandidates(convertWithReceivers( memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java index d20a8d5fb70..83fe17f8dd7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/TracingStrategyForInvoke.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.lang.resolve.calls.tasks; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; @@ -27,14 +28,18 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.Collection; import static org.jetbrains.jet.lang.diagnostics.Errors.FUNCTION_EXPECTED; +import static org.jetbrains.jet.lang.diagnostics.Errors.NO_RECEIVER_ALLOWED; import static org.jetbrains.jet.lang.resolve.BindingContext.CALL; import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL; public class TracingStrategyForInvoke extends AbstractTracingStrategy { + private static final Logger LOG = Logger.getInstance(TracingStrategyForInvoke.class); + private final JetType calleeType; public TracingStrategyForInvoke( @@ -74,13 +79,26 @@ public class TracingStrategyForInvoke extends AbstractTracingStrategy { @Override public void unresolvedReference(@NotNull BindingTrace trace) { - trace.report(FUNCTION_EXPECTED.on(reference, reference, calleeType)); + functionExpectedOrNoReceiverAllowed(trace); } @Override public void unresolvedReferenceWrongReceiver( @NotNull BindingTrace trace, @NotNull Collection> candidates ) { - trace.report(FUNCTION_EXPECTED.on(reference, reference, calleeType)); + functionExpectedOrNoReceiverAllowed(trace); + } + + private void functionExpectedOrNoReceiverAllowed(BindingTrace trace) { + if (KotlinBuiltIns.getInstance().isFunctionType(calleeType)) { + //LOG.assert + if (!call.getExplicitReceiver().exists()) { + LOG.error("'Invoke' is not found on expression of function type (" + calleeType + "): " + call.getCallElement().getText()); + } + trace.report(NO_RECEIVER_ALLOWED.on(reference)); + } + else { + trace.report(FUNCTION_EXPECTED.on(reference, reference, calleeType)); + } } }