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 import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory;
052
053 /**
054 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
055 *
056 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
057 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
058 *
059 * context#1. calls: 'b.foo' 'invoke(1)'
060 * context#2. calls: 'foo' 'b.invoke(1)'
061 *
062 * If success VariableAsFunctionResolvedCall is created.
063 */
064 public class CallTransformer<D extends CallableDescriptor, F extends D> {
065 private CallTransformer() {}
066
067 /**
068 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
069 */
070 @NotNull
071 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
072 @NotNull ResolutionTask<D, F> task,
073 @NotNull TemporaryBindingTrace candidateTrace
074 ) {
075 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
076 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing));
077 }
078
079 /**
080 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
081 * the resolved call from callCandidateResolutionContext otherwise
082 */
083 @NotNull
084 public Collection<MutableResolvedCall<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
085 @NotNull CallResolver callResolver,
086 @NotNull ResolutionTask<D, F> task
087 ) {
088 return Collections.singleton((MutableResolvedCall<F>) callCandidateResolutionContext.candidateCall);
089 }
090
091
092 public static CallTransformer<VariableDescriptor, VariableDescriptor> PROPERTY_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
093
094 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
095 @NotNull
096 @Override
097 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
098 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace) {
099
100 if (candidate.getDescriptor() instanceof FunctionDescriptor) {
101 return super.createCallContexts(candidate, task, candidateTrace);
102 }
103
104 assert candidate.getDescriptor() instanceof VariableDescriptor;
105
106 boolean hasReceiver = candidate.getReceiverArgument().exists();
107 Call variableCall = stripCallArguments(task.call);
108 ResolutionCandidate<CallableDescriptor> variableCandidate = getVariableCallCandidate(candidate, variableCall);
109 if (!hasReceiver) {
110 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
111 ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
112 return Collections.singleton(context);
113 }
114 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
115 variableCandidate, variableCall, candidateTrace, task, ReceiverValue.NO_RECEIVER);
116
117 Call variableCallWithoutReceiver = stripReceiver(variableCall);
118 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
119 variableCandidate.getCall(),
120 variableCandidate.getDescriptor(),
121 variableCandidate.getThisObject(),
122 ReceiverValue.NO_RECEIVER,
123 ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
124
125 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
126 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver());
127
128 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
129 }
130
131 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(
132 @NotNull ResolutionCandidate<CallableDescriptor> candidate, @NotNull Call call, @NotNull TemporaryBindingTrace temporaryTrace,
133 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull ReceiverValue receiverValue
134 ) {
135 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
136 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
137 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call, receiverValue);
138 }
139
140 @NotNull
141 private ResolutionCandidate<CallableDescriptor> getVariableCallCandidate(
142 @NotNull ResolutionCandidate<CallableDescriptor> candidate,
143 @NotNull Call variableCall
144 ) {
145 return ResolutionCandidate.create(
146 variableCall,
147 candidate.getDescriptor(),
148 candidate.getThisObject(),
149 candidate.getReceiverArgument(),
150 candidate.getExplicitReceiverKind(),
151 candidate.isSafeCall());
152 }
153
154 private Call stripCallArguments(@NotNull Call call) {
155 return new DelegatingCall(call) {
156 @Override
157 public JetValueArgumentList getValueArgumentList() {
158 return null;
159 }
160
161 @NotNull
162 @Override
163 public List<? extends ValueArgument> getValueArguments() {
164 return Collections.emptyList();
165 }
166
167 @NotNull
168 @Override
169 public List<JetFunctionLiteralArgument> getFunctionLiteralArguments() {
170 return Collections.emptyList();
171 }
172
173 @NotNull
174 @Override
175 public List<JetTypeProjection> getTypeArguments() {
176 return Collections.emptyList();
177 }
178
179 @Override
180 public JetTypeArgumentList getTypeArgumentList() {
181 return null;
182 }
183
184 @NotNull
185 @Override
186 public JetElement getCallElement() {
187 JetExpression calleeExpression = getCalleeExpression();
188 assert calleeExpression != null : "No callee expression: " + getCallElement().getText();
189
190 return calleeExpression;
191 }
192 };
193 }
194
195 private Call stripReceiver(@NotNull Call variableCall) {
196 return new DelegatingCall(variableCall) {
197 @NotNull
198 @Override
199 public ReceiverValue getExplicitReceiver() {
200 return ReceiverValue.NO_RECEIVER;
201 }
202 };
203 }
204
205 @NotNull
206 @Override
207 public Collection<MutableResolvedCall<FunctionDescriptor>> transformCall(
208 @NotNull CallCandidateResolutionContext<CallableDescriptor> context,
209 @NotNull CallResolver callResolver,
210 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task
211 ) {
212 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
213 if (descriptor instanceof FunctionDescriptor) {
214 return super.transformCall(context, callResolver, task);
215 }
216
217 assert descriptor instanceof VariableDescriptor;
218 JetType returnType = descriptor.getReturnType();
219 if (returnType == null) {
220 return Collections.emptyList();
221 }
222
223 final MutableResolvedCall<VariableDescriptor> variableResolvedCall = (MutableResolvedCall)context.candidateCall;
224
225 JetExpression calleeExpression = task.call.getCalleeExpression();
226 if (calleeExpression == null) return Collections.emptyList();
227
228 ExpressionReceiver variableReceiver = new ExpressionReceiver(calleeExpression, variableResolvedCall.getResultingDescriptor().getType());
229 Call functionCall = new CallForImplicitInvoke(context.explicitExtensionReceiverForInvoke, variableReceiver, task.call);
230
231 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
232 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
233 context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
234 functionCall, context.checkArguments, context.dataFlowInfoForArguments);
235
236 // 'invoke' call resolve
237 TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(
238 calleeExpression, functionCall, variableReceiver.getType());
239 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallForInvoke(
240 basicCallResolutionContext, tracingForInvoke);
241 Collection<MutableResolvedCall<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
242
243 return Collections2.transform(calls, new Function<MutableResolvedCall<FunctionDescriptor>, MutableResolvedCall<FunctionDescriptor>>() {
244 @Override
245 public MutableResolvedCall<FunctionDescriptor> apply(MutableResolvedCall<FunctionDescriptor> functionResolvedCall) {
246 return new VariableAsFunctionResolvedCallImpl(functionResolvedCall, variableResolvedCall);
247 }
248 });
249 }
250 };
251
252 public static class CallForImplicitInvoke extends DelegatingCall {
253 final Call outerCall;
254 final ReceiverValue explicitExtensionReceiver;
255 final ExpressionReceiver calleeExpressionAsThisObject;
256 final JetSimpleNameExpression fakeInvokeExpression;
257
258 public CallForImplicitInvoke(
259 @NotNull ReceiverValue explicitExtensionReceiver,
260 @NotNull ExpressionReceiver calleeExpressionAsThisObject,
261 @NotNull Call call
262 ) {
263 super(call);
264 this.outerCall = call;
265 this.explicitExtensionReceiver = explicitExtensionReceiver;
266 this.calleeExpressionAsThisObject = calleeExpressionAsThisObject;
267 this.fakeInvokeExpression = (JetSimpleNameExpression) JetPsiFactory(call.getCallElement()).createExpression( "invoke");
268 }
269
270 @NotNull
271 @Override
272 public ReceiverValue getExplicitReceiver() {
273 return explicitExtensionReceiver;
274 }
275
276 @NotNull
277 @Override
278 public ExpressionReceiver getThisObject() {
279 return calleeExpressionAsThisObject;
280 }
281
282 @Override
283 public JetExpression getCalleeExpression() {
284 return fakeInvokeExpression;
285 }
286
287 @NotNull
288 @Override
289 public JetElement getCallElement() {
290 return outerCall.getCallElement();
291 }
292
293 @NotNull
294 @Override
295 public CallType getCallType() {
296 return CallType.INVOKE;
297 }
298
299 @NotNull
300 public Call getOuterCall() {
301 return outerCall;
302 }
303 }
304 }