changed CallTransformer responsible for resolving second call ('invoke') for 'variable as function' case
This commit is contained in:
-118
@@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2012 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.calls;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author svtk
|
|
||||||
*/
|
|
||||||
public interface CallTransformationStrategy<D extends CallableDescriptor, R extends D> {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
CallResolutionContext<D> createCallContext(@NotNull ResolutionCandidate<D> candidate,
|
|
||||||
@NotNull ResolutionTask<D> task,
|
|
||||||
@NotNull BindingTrace trace,
|
|
||||||
@NotNull TracingStrategy tracing);
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
Collection<ResolvedCallImpl<R>> transformResultCall(@NotNull CallResolutionContext<D> callResolutionContext,
|
|
||||||
@NotNull CallResolver callResolver,
|
|
||||||
@NotNull ResolutionTask<D> task);
|
|
||||||
|
|
||||||
CallTransformationStrategy<VariableDescriptor, VariableDescriptor>
|
|
||||||
PROPERTY_CALL_TRANSFORMATION_STRATEGY = new CallTransformationStrategy<VariableDescriptor, VariableDescriptor>() {
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public CallResolutionContext<VariableDescriptor> createCallContext(@NotNull ResolutionCandidate<VariableDescriptor> candidate,
|
|
||||||
@NotNull ResolutionTask<VariableDescriptor> task, @NotNull BindingTrace trace, @NotNull TracingStrategy tracing) {
|
|
||||||
ResolvedCallImpl<VariableDescriptor> candidateCall = ResolvedCallImpl.create(candidate);
|
|
||||||
return new CallResolutionContext<VariableDescriptor>(candidateCall, task, trace, tracing);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Collection<ResolvedCallImpl<VariableDescriptor>> transformResultCall(@NotNull CallResolutionContext<VariableDescriptor> context,
|
|
||||||
@NotNull CallResolver callResolver, @NotNull ResolutionTask<VariableDescriptor> task) {
|
|
||||||
return Collections.singleton(context.candidateCall);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CallTransformationStrategy<FunctionDescriptor, FunctionDescriptor>
|
|
||||||
FUNCTION_CALL_TRANSFORMATION_STRATEGY = new CallTransformationStrategy<FunctionDescriptor, FunctionDescriptor>() {
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public CallResolutionContext<FunctionDescriptor> createCallContext(@NotNull ResolutionCandidate<FunctionDescriptor> candidate,
|
|
||||||
@NotNull ResolutionTask<FunctionDescriptor> task,
|
|
||||||
@NotNull BindingTrace trace,
|
|
||||||
@NotNull TracingStrategy tracing) {
|
|
||||||
if (candidate.getDescriptor() instanceof FunctionDescriptor) {
|
|
||||||
return new CallResolutionContext<FunctionDescriptor>(ResolvedCallImpl.create(candidate), task, trace, tracing);
|
|
||||||
}
|
|
||||||
assert candidate.getDescriptor() instanceof VariableDescriptor;
|
|
||||||
Call propertyCall = new DelegatingCall(task.call) {
|
|
||||||
@Override
|
|
||||||
public JetValueArgumentList getValueArgumentList() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public List<JetExpression> getFunctionLiteralArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public List<JetTypeProjection> getTypeArguments() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JetTypeArgumentList getTypeArgumentList() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return new CallResolutionContext<FunctionDescriptor>(ResolvedCallImpl.create(candidate), task, trace, tracing, propertyCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Collection<ResolvedCallImpl<FunctionDescriptor>> transformResultCall(@NotNull CallResolutionContext<FunctionDescriptor> context,
|
|
||||||
@NotNull CallResolver callResolver, @NotNull ResolutionTask<FunctionDescriptor> task) {
|
|
||||||
FunctionDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
|
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
|
||||||
return Collections.singleton(context.candidateCall);
|
|
||||||
}
|
|
||||||
assert descriptor instanceof VariableDescriptor;
|
|
||||||
BasicResolutionContext basicResolutionContext =
|
|
||||||
BasicResolutionContext.create(context.trace, context.scope, task.call, context.expectedType, context.dataFlowInfo);
|
|
||||||
OverloadResolutionResults<FunctionDescriptor> results =
|
|
||||||
callResolver.resolveCallWithGivenName(basicResolutionContext, task.reference, "invoke");
|
|
||||||
return ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2012 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.lang.resolve.calls;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Collections2;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
|
||||||
|
*
|
||||||
|
* For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
|
||||||
|
* CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
|
||||||
|
*
|
||||||
|
* context#1. calls: 'b.foo' 'invoke(1)'
|
||||||
|
* context#2. calls: 'foo' 'b.invoke(1)'
|
||||||
|
*
|
||||||
|
* If success VariableAsFunctionResolvedCall is created.
|
||||||
|
*
|
||||||
|
* @author svtk
|
||||||
|
*/
|
||||||
|
public class CallTransformer<D extends CallableDescriptor, F extends D> {
|
||||||
|
private CallTransformer() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Collection<CallResolutionContext<D, F>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
|
||||||
|
@NotNull ResolutionTask<D, F> task,
|
||||||
|
@NotNull TemporaryBindingTrace temporaryTrace) {
|
||||||
|
|
||||||
|
ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, temporaryTrace);
|
||||||
|
return Collections.singleton(CallResolutionContext.create(candidateCall, task, temporaryTrace, task.tracing));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
|
||||||
|
* the resolved call from callResolutionContext otherwise
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Collection<ResolvedCallWithTrace<F>> transformCall(@NotNull CallResolutionContext<D, F> callResolutionContext,
|
||||||
|
@NotNull CallResolver callResolver,
|
||||||
|
@NotNull ResolutionTask<D, F> task) {
|
||||||
|
|
||||||
|
return Collections.singleton((ResolvedCallWithTrace<F>)callResolutionContext.candidateCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static CallTransformer<VariableDescriptor, VariableDescriptor> PROPERTY_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
|
||||||
|
|
||||||
|
public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<CallResolutionContext<CallableDescriptor, FunctionDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
|
||||||
|
@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace temporaryTrace) {
|
||||||
|
|
||||||
|
if (candidate.getDescriptor() instanceof FunctionDescriptor) {
|
||||||
|
return super.createCallContexts(candidate, task, temporaryTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert candidate.getDescriptor() instanceof VariableDescriptor;
|
||||||
|
|
||||||
|
boolean hasReceiver = candidate.getReceiverArgument().exists();
|
||||||
|
Call variableCall = stripCallArguments(task);
|
||||||
|
if (!hasReceiver) {
|
||||||
|
CallResolutionContext<CallableDescriptor, FunctionDescriptor> context = CallResolutionContext.create(
|
||||||
|
ResolvedCallImpl.create(candidate, temporaryTrace), task, temporaryTrace, task.tracing, variableCall);
|
||||||
|
return Collections.singleton(context);
|
||||||
|
}
|
||||||
|
Call variableCallWithoutReceiver = stripReceiver(variableCall);
|
||||||
|
CallResolutionContext<CallableDescriptor, FunctionDescriptor> contextWithReceiver = createContextWithChainedTrace(
|
||||||
|
candidate, variableCall, temporaryTrace, task);
|
||||||
|
|
||||||
|
ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
|
||||||
|
candidate.getDescriptor(), candidate.getThisObject(), ReceiverDescriptor.NO_RECEIVER);
|
||||||
|
|
||||||
|
CallResolutionContext<CallableDescriptor, FunctionDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
|
||||||
|
candidateWithoutReceiver, variableCallWithoutReceiver, temporaryTrace, task);
|
||||||
|
|
||||||
|
contextWithoutReceiver.delayedReceiverForVariableAsFunctionSecondCall = variableCall.getExplicitReceiver();
|
||||||
|
|
||||||
|
return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallResolutionContext<CallableDescriptor, FunctionDescriptor> createContextWithChainedTrace(ResolutionCandidate<CallableDescriptor> candidate,
|
||||||
|
Call call, TemporaryBindingTrace temporaryTrace, ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
|
||||||
|
|
||||||
|
ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace);
|
||||||
|
ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace);
|
||||||
|
return CallResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Call stripCallArguments(@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
|
||||||
|
return new DelegatingCall(task.call) {
|
||||||
|
@Override
|
||||||
|
public JetValueArgumentList getValueArgumentList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<? extends ValueArgument> getValueArguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<JetExpression> getFunctionLiteralArguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<JetTypeProjection> getTypeArguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetTypeArgumentList getTypeArgumentList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Call stripReceiver(@NotNull Call variableCall) {
|
||||||
|
return new DelegatingCall(variableCall) {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ReceiverDescriptor getExplicitReceiver() {
|
||||||
|
return ReceiverDescriptor.NO_RECEIVER;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<ResolvedCallWithTrace<FunctionDescriptor>> transformCall(@NotNull final CallResolutionContext<CallableDescriptor, FunctionDescriptor> context,
|
||||||
|
@NotNull CallResolver callResolver, @NotNull final ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
|
||||||
|
|
||||||
|
final CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
|
||||||
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
|
return super.transformCall(context, callResolver, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert descriptor instanceof VariableDescriptor;
|
||||||
|
JetType returnType = descriptor.getReturnType();
|
||||||
|
if (returnType == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
final ResolvedCallWithTrace<VariableDescriptor> variableResolvedCall = (ResolvedCallWithTrace)context.candidateCall;
|
||||||
|
|
||||||
|
Call functionCall = createFunctionCall(context, task, returnType);
|
||||||
|
|
||||||
|
final TemporaryBindingTrace variableCallTrace = context.candidateCall.getTrace();
|
||||||
|
BasicResolutionContext basicResolutionContext = BasicResolutionContext.create(variableCallTrace, context.scope, functionCall, context.expectedType, context.dataFlowInfo);
|
||||||
|
|
||||||
|
// 'invoke' call resolve
|
||||||
|
OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithGivenName(basicResolutionContext, task.reference, "invoke");
|
||||||
|
Collection<ResolvedCallWithTrace<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
|
||||||
|
|
||||||
|
return Collections2.transform(calls, new Function<ResolvedCallWithTrace<FunctionDescriptor>, ResolvedCallWithTrace<FunctionDescriptor>>() {
|
||||||
|
@Override
|
||||||
|
public ResolvedCallWithTrace<FunctionDescriptor> apply(ResolvedCallWithTrace<FunctionDescriptor> functionResolvedCall) {
|
||||||
|
return new VariableAsFunctionResolvedCall(functionResolvedCall, variableResolvedCall);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Call createFunctionCall(final CallResolutionContext<CallableDescriptor, FunctionDescriptor> context,
|
||||||
|
final ResolutionTask<CallableDescriptor, FunctionDescriptor> task, JetType returnType) {
|
||||||
|
|
||||||
|
final ExpressionReceiver receiverFromVariable = new ExpressionReceiver(task.reference, returnType);
|
||||||
|
final JetSimpleNameExpression invokeExpression = (JetSimpleNameExpression) JetPsiFactory.createExpression(
|
||||||
|
task.call.getCallElement().getProject(), "invoke");
|
||||||
|
|
||||||
|
return new DelegatingCall(task.call) {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ReceiverDescriptor getExplicitReceiver() {
|
||||||
|
return context.delayedReceiverForVariableAsFunctionSecondCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ReceiverDescriptor getThisObject() {
|
||||||
|
return receiverFromVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetExpression getCalleeExpression() {
|
||||||
|
return invokeExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public PsiElement getCallElement() {
|
||||||
|
if (task.call.getCallElement() instanceof JetCallElement) {
|
||||||
|
//to report errors properly
|
||||||
|
JetValueArgumentList list = ((JetCallElement)task.call.getCallElement()).getValueArgumentList();
|
||||||
|
if (list != null) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return invokeExpression;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user