001 /*
002 * Copyright 2010-2013 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.jet.lang.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 org.jetbrains.annotations.NotNull;
023 import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
024 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
025 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.ChainedTemporaryBindingTrace;
028 import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
029 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
030 import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
031 import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
032 import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
033 import org.jetbrains.jet.lang.resolve.calls.model.MutableResolvedCall;
034 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
035 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCallImpl;
036 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
037 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
038 import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
039 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
040 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
041 import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategyForInvoke;
042 import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall;
043 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
044 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
045 import org.jetbrains.jet.lang.types.JetType;
046
047 import java.util.Collection;
048 import java.util.Collections;
049 import java.util.List;
050
051 /**
052 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
053 *
054 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
055 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
056 *
057 * context#1. calls: 'b.foo' 'invoke(1)'
058 * context#2. calls: 'foo' 'b.invoke(1)'
059 *
060 * If success VariableAsFunctionResolvedCall is created.
061 */
062 public class CallTransformer<D extends CallableDescriptor, F extends D> {
063 private CallTransformer() {}
064
065 /**
066 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
067 */
068 @NotNull
069 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
070 @NotNull ResolutionTask<D, F> task,
071 @NotNull TemporaryBindingTrace candidateTrace
072 ) {
073 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
074 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing));
075 }
076
077 /**
078 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
079 * the resolved call from callCandidateResolutionContext otherwise
080 */
081 @NotNull
082 public Collection<MutableResolvedCall<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
083 @NotNull CallResolver callResolver,
084 @NotNull ResolutionTask<D, F> task
085 ) {
086 return Collections.singleton((MutableResolvedCall<F>) callCandidateResolutionContext.candidateCall);
087 }
088
089
090 public static CallTransformer<VariableDescriptor, VariableDescriptor> PROPERTY_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
091
092 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
093 @NotNull
094 @Override
095 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
096 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace) {
097
098 if (candidate.getDescriptor() instanceof FunctionDescriptor) {
099 return super.createCallContexts(candidate, task, candidateTrace);
100 }
101
102 assert candidate.getDescriptor() instanceof VariableDescriptor;
103
104 boolean hasReceiver = candidate.getReceiverArgument().exists();
105 Call variableCall = stripCallArguments(task.call);
106 ResolutionCandidate<CallableDescriptor> variableCandidate = getVariableCallCandidate(candidate, variableCall);
107 if (!hasReceiver) {
108 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
109 ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
110 return Collections.singleton(context);
111 }
112 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
113 variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER);
114
115 Call variableCallWithoutReceiver = stripReceiver(variableCall);
116 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
117 variableCandidate.getCall(),
118 variableCandidate.getDescriptor(),
119 variableCandidate.getThisObject(),
120 ReceiverValue.NO_RECEIVER,
121 ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
122
123 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
124 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver());
125
126 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
127 }
128
129 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
130 @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
131 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull ReceiverValue receiverValue
132 ) {
133 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
134 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
135 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue);
136 }
137
138 @NotNull
139 private ResolutionCandidate<CallableDescriptor> getVariableCallCandidate(
140 @NotNull ResolutionCandidate<CallableDescriptor> candidate,
141 @NotNull Call variableCall
142 ) {
143 return ResolutionCandidate.create(
144 variableCall,
145 candidate.getDescriptor(),
146 candidate.getThisObject(),
147 candidate.getReceiverArgument(),
148 candidate.getExplicitReceiverKind(),
149 candidate.isSafeCall());
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<JetExpression> 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 @NotNull
196 @Override
197 public ReceiverValue getExplicitReceiver() {
198 return ReceiverValue.NO_RECEIVER;
199 }
200 };
201 }
202
203 @NotNull
204 @Override
205 public Collection<MutableResolvedCall<FunctionDescriptor>> transformCall(
206 @NotNull CallCandidateResolutionContext<CallableDescriptor> context,
207 @NotNull CallResolver callResolver,
208 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task
209 ) {
210 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
211 if (descriptor instanceof FunctionDescriptor) {
212 return super.transformCall(context, callResolver, task);
213 }
214
215 assert descriptor instanceof VariableDescriptor;
216 JetType returnType = descriptor.getReturnType();
217 if (returnType == null) {
218 return Collections.emptyList();
219 }
220
221 final MutableResolvedCall<VariableDescriptor> variableResolvedCall = (MutableResolvedCall)context.candidateCall;
222
223 JetExpression calleeExpression = task.call.getCalleeExpression();
224 if (calleeExpression == null) return Collections.emptyList();
225
226 ExpressionReceiver variableReceiver = new ExpressionReceiver(calleeExpression, variableResolvedCall.getResultingDescriptor().getType());
227 Call functionCall = new CallForImplicitInvoke(context.explicitExtensionReceiverForInvoke, variableReceiver, task.call);
228
229 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
230 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
231 context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
232 functionCall, context.checkArguments, context.dataFlowInfoForArguments);
233
234 // 'invoke' call resolve
235 TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(
236 calleeExpression, functionCall, variableReceiver.getType());
237 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
238 basicCallResolutionContext, tracingForInvoke);
239 Collection<MutableResolvedCall<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
240
241 return Collections2.transform(calls, new Function<MutableResolvedCall<FunctionDescriptor>, MutableResolvedCall<FunctionDescriptor>>() {
242 @Override
243 public MutableResolvedCall<FunctionDescriptor> apply(MutableResolvedCall<FunctionDescriptor> functionResolvedCall) {
244 return new VariableAsFunctionResolvedCallImpl(functionResolvedCall, variableResolvedCall);
245 }
246 });
247 }
248 };
249
250 public static class CallForImplicitInvoke extends DelegatingCall {
251 final Call outerCall;
252 final ReceiverValue explicitExtensionReceiver;
253 final ExpressionReceiver calleeExpressionAsThisObject;
254 final JetSimpleNameExpression fakeInvokeExpression;
255
256 public CallForImplicitInvoke(
257 @NotNull ReceiverValue explicitExtensionReceiver,
258 @NotNull ExpressionReceiver calleeExpressionAsThisObject,
259 @NotNull Call call
260 ) {
261 super(call);
262 this.outerCall = call;
263 this.explicitExtensionReceiver = explicitExtensionReceiver;
264 this.calleeExpressionAsThisObject = calleeExpressionAsThisObject;
265 this.fakeInvokeExpression = (JetSimpleNameExpression) JetPsiFactory.createExpression(call.getCallElement().getProject(), "invoke");
266 }
267
268 @NotNull
269 @Override
270 public ReceiverValue getExplicitReceiver() {
271 return explicitExtensionReceiver;
272 }
273
274 @NotNull
275 @Override
276 public ReceiverValue getThisObject() {
277 return calleeExpressionAsThisObject;
278 }
279
280 @Override
281 public JetExpression getCalleeExpression() {
282 return fakeInvokeExpression;
283 }
284
285 @NotNull
286 @Override
287 public JetElement getCallElement() {
288 return outerCall.getCallElement();
289 }
290
291 @NotNull
292 @Override
293 public CallType getCallType() {
294 return CallType.INVOKE;
295 }
296
297 @NotNull
298 public Call getOuterCall() {
299 return outerCall;
300 }
301 }
302 }