001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve.calls;
018
019 import com.google.common.base.Function;
020 import com.google.common.collect.Collections2;
021 import com.google.common.collect.Lists;
022 import com.intellij.lang.ASTNode;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.kotlin.descriptors.CallableDescriptor;
026 import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
027 import org.jetbrains.kotlin.descriptors.VariableDescriptor;
028 import org.jetbrains.kotlin.psi.*;
029 import org.jetbrains.kotlin.resolve.ChainedTemporaryBindingTrace;
030 import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
031 import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
032 import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
033 import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext;
034 import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
035 import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
036 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
037 import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl;
038 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
039 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
040 import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
041 import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
042 import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionTask;
043 import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyForInvoke;
044 import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall;
045 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
046 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
047 import org.jetbrains.kotlin.types.JetType;
048 import org.jetbrains.kotlin.types.expressions.OperatorConventions;
049
050 import java.util.Collection;
051 import java.util.Collections;
052 import java.util.List;
053
054 import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
055
056 /**
057 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
058 *
059 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
060 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
061 *
062 * context#1. calls: 'b.foo' 'invoke(1)'
063 * context#2. calls: 'foo' 'b.invoke(1)'
064 *
065 * If success VariableAsFunctionResolvedCall is created.
066 */
067 public class CallTransformer<D extends CallableDescriptor, F extends D> {
068 private CallTransformer() {}
069
070 /**
071 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
072 */
073 @NotNull
074 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
075 @NotNull ResolutionTask<D, F> task,
076 @NotNull TemporaryBindingTrace candidateTrace
077 ) {
078 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
079 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing));
080 }
081
082 /**
083 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
084 * the resolved call from callCandidateResolutionContext otherwise
085 */
086 @NotNull
087 public Collection<MutableResolvedCall<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
088 @NotNull CallResolver callResolver,
089 @NotNull ResolutionTask<D, F> task
090 ) {
091 return Collections.singleton((MutableResolvedCall<F>) callCandidateResolutionContext.candidateCall);
092 }
093
094
095 public static CallTransformer<CallableDescriptor, CallableDescriptor> MEMBER_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, CallableDescriptor>();
096
097 public static CallTransformer<VariableDescriptor, VariableDescriptor> VARIABLE_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
098
099 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
100 @NotNull
101 @Override
102 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
103 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace) {
104
105 if (candidate.getDescriptor() instanceof FunctionDescriptor) {
106 return super.createCallContexts(candidate, task, candidateTrace);
107 }
108
109 assert candidate.getDescriptor() instanceof VariableDescriptor;
110
111 boolean hasReceiver = candidate.getExtensionReceiver().exists();
112 Call variableCall = stripCallArguments(task.call);
113 ResolutionCandidate<CallableDescriptor> variableCandidate = ResolutionCandidate.create(
114 variableCall,
115 candidate.getDescriptor(),
116 candidate.getDispatchReceiver(),
117 candidate.getExtensionReceiver(),
118 candidate.getExplicitReceiverKind(),
119 null);
120 if (!hasReceiver) {
121 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
122 ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
123 task, candidateTrace, task.tracing, variableCall);
124 return Collections.singleton(context);
125 }
126 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
127 variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER);
128
129 Call variableCallWithoutReceiver = stripReceiver(variableCall);
130 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
131 variableCallWithoutReceiver,
132 candidate.getDescriptor(),
133 candidate.getDispatchReceiver(),
134 ReceiverValue.NO_RECEIVER,
135 ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
136
137 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
138 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver());
139
140 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
141 }
142
143 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
144 @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
145 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull ReceiverValue receiverValue
146 ) {
147 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
148 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
149 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue);
150 }
151
152 private Call stripCallArguments(@NotNull Call call) {
153 return new DelegatingCall(call) {
154 @Override
155 public JetValueArgumentList getValueArgumentList() {
156 return null;
157 }
158
159 @NotNull
160 @Override
161 public List<? extends ValueArgument> getValueArguments() {
162 return Collections.emptyList();
163 }
164
165 @NotNull
166 @Override
167 public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
168 return Collections.emptyList();
169 }
170
171 @NotNull
172 @Override
173 public List<JetTypeProjection> getTypeArguments() {
174 return Collections.emptyList();
175 }
176
177 @Override
178 public JetTypeArgumentList getTypeArgumentList() {
179 return null;
180 }
181
182 @NotNull
183 @Override
184 public JetElement getCallElement() {
185 JetExpression calleeExpression = getCalleeExpression();
186 assert calleeExpression != null : "No callee expression: " + getCallElement().getText();
187
188 return calleeExpression;
189 }
190 };
191 }
192
193 private Call stripReceiver(@NotNull Call variableCall) {
194 return new DelegatingCall(variableCall) {
195 @Nullable
196 @Override
197 public ASTNode getCallOperationNode() {
198 return null;
199 }
200
201 @NotNull
202 @Override
203 public ReceiverValue getExplicitReceiver() {
204 return ReceiverValue.NO_RECEIVER;
205 }
206 };
207 }
208
209 @NotNull
210 @Override
211 public Collection<MutableResolvedCall<FunctionDescriptor>> transformCall(
212 @NotNull CallCandidateResolutionContext<CallableDescriptor> context,
213 @NotNull CallResolver callResolver,
214 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task
215 ) {
216 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
217 if (descriptor instanceof FunctionDescriptor) {
218 return super.transformCall(context, callResolver, task);
219 }
220
221 assert descriptor instanceof VariableDescriptor;
222 JetType returnType = descriptor.getReturnType();
223 if (returnType == null) {
224 return Collections.emptyList();
225 }
226
227 final MutableResolvedCall<VariableDescriptor> variableResolvedCall = (MutableResolvedCall)context.candidateCall;
228
229 JetExpression calleeExpression = task.call.getCalleeExpression();
230 if (calleeExpression == null) return Collections.emptyList();
231
232 ExpressionReceiver variableReceiver = new ExpressionReceiver(calleeExpression, variableResolvedCall.getResultingDescriptor().getType());
233 Call functionCall = new CallForImplicitInvoke(context.explicitExtensionReceiverForInvoke, variableReceiver, task.call);
234
235 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
236 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
237 context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
238 functionCall, context.checkArguments, context.dataFlowInfoForArguments);
239
240 // 'invoke' call resolve
241 TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(
242 calleeExpression, functionCall, variableReceiver.getType());
243 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
244 basicCallResolutionContext, tracingForInvoke);
245 Collection<MutableResolvedCall<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
246
247 return Collections2.transform(calls, new Function<MutableResolvedCall<FunctionDescriptor>, MutableResolvedCall<FunctionDescriptor>>() {
248 @Override
249 public MutableResolvedCall<FunctionDescriptor> apply(MutableResolvedCall<FunctionDescriptor> functionResolvedCall) {
250 return new VariableAsFunctionResolvedCallImpl(functionResolvedCall, variableResolvedCall);
251 }
252 });
253 }
254 };
255
256 public static class CallForImplicitInvoke extends DelegatingCall {
257 private final Call outerCall;
258 private final ReceiverValue explicitExtensionReceiver;
259 private final ExpressionReceiver calleeExpressionAsDispatchReceiver;
260 private final JetSimpleNameExpression fakeInvokeExpression;
261
262 public CallForImplicitInvoke(
263 @NotNull ReceiverValue explicitExtensionReceiver,
264 @NotNull ExpressionReceiver calleeExpressionAsDispatchReceiver,
265 @NotNull Call call
266 ) {
267 super(call);
268 this.outerCall = call;
269 this.explicitExtensionReceiver = explicitExtensionReceiver;
270 this.calleeExpressionAsDispatchReceiver = calleeExpressionAsDispatchReceiver;
271 this.fakeInvokeExpression =
272 (JetSimpleNameExpression) JetPsiFactory(call.getCallElement()).createExpression(OperatorConventions.INVOKE.asString());
273 }
274
275 @Nullable
276 @Override
277 public ASTNode getCallOperationNode() {
278 // if an explicit receiver corresponds to the implicit invoke, there is a corresponding call operation node:
279 // a.b() or a?.b() (where b has an extension function type);
280 // otherwise it's implicit
281 return explicitExtensionReceiver.exists() ? super.getCallOperationNode() : null;
282 }
283
284 @NotNull
285 @Override
286 public ReceiverValue getExplicitReceiver() {
287 return explicitExtensionReceiver;
288 }
289
290 @NotNull
291 @Override
292 public ExpressionReceiver getDispatchReceiver() {
293 return calleeExpressionAsDispatchReceiver;
294 }
295
296 @Override
297 public JetExpression getCalleeExpression() {
298 return fakeInvokeExpression;
299 }
300
301 @NotNull
302 @Override
303 public CallType getCallType() {
304 return CallType.INVOKE;
305 }
306
307 @NotNull
308 public Call getOuterCall() {
309 return outerCall;
310 }
311 }
312 }