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)
This commit is contained in:
Svetlana Isakova
2014-10-03 14:55:06 +04:00
parent c0eb894bd9
commit 29fa87ee7c
5 changed files with 33 additions and 17 deletions
@@ -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(
@@ -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;
@@ -32,7 +32,7 @@ public trait CallableDescriptorCollector<D : CallableDescriptor> {
public fun getMembersByName(receiver: JetType, name: Name, bindingTrace: BindingTrace): Collection<D>
public fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<D>
public fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<D>
}
private val FUNCTIONS_COLLECTOR = FilteredCollector(FunctionCollector)
@@ -66,8 +66,8 @@ private object FunctionCollector : CallableDescriptorCollector<FunctionDescripto
return receiverScope.getFunctions(name) + getConstructors(receiverScope, name)
}
override fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<FunctionDescriptor> {
return scope.getFunctions(name)
override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<FunctionDescriptor> {
return scope.getFunctions(name).filter { it.getExtensionReceiverParameter() != null }
}
private fun getConstructors(scope: JetScope, name: Name): Collection<FunctionDescriptor> {
@@ -106,7 +106,8 @@ private object VariableCollector : CallableDescriptorCollector<VariableDescripto
return (memberScope.getProperties(name) + getFakeDescriptorForObject(memberScope, name)).filterNotNull()
}
override fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<VariableDescriptor> {
override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<VariableDescriptor> {
// 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<VariableDescripto
return filterProperties(VARIABLES_COLLECTOR.getMembersByName(receiver, name, bindingTrace))
}
override fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<VariableDescriptor> {
return filterProperties(VARIABLES_COLLECTOR.getNonMembersByName(scope, name, bindingTrace))
override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<VariableDescriptor> {
return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, bindingTrace))
}
override fun toString() = "PROPERTIES"
@@ -142,8 +143,8 @@ private class FilteredCollector<D : CallableDescriptor>(private val delegate: Ca
return filterOutMembersFromLibrarySource(delegate.getMembersByName(receiver, name, bindingTrace))
}
override fun getNonMembersByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<D> {
return filterOutMembersFromLibrarySource(delegate.getNonMembersByName(scope, name, bindingTrace))
override fun getExtensionsByName(scope: JetScope, name: Name, bindingTrace: BindingTrace): Collection<D> {
return filterOutMembersFromLibrarySource(delegate.getExtensionsByName(scope, name, bindingTrace))
}
override fun toString(): String {
@@ -153,7 +153,7 @@ public class TaskPrioritizer {
}
//extensions
Collection<ResolutionCandidate<D>> 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<D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c,
@NotNull ExplicitReceiverKind receiverKind
) {
Collection<D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
Collection<D> memberExtensions = callableDescriptorCollector.getExtensionsByName(
dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace);
c.result.addCandidates(convertWithReceivers(
memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call));
@@ -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 <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
@NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> 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));
}
}
}