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 com.intellij.psi.PsiElement;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
025 import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
026 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
027 import org.jetbrains.jet.lang.psi.*;
028 import org.jetbrains.jet.lang.resolve.ChainedTemporaryBindingTrace;
029 import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
030 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
031 import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
032 import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
033 import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
034 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
036 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
037 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
038 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
039 import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
040 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
041 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
042 import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall;
043 import org.jetbrains.jet.lang.resolve.name.Name;
044 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
045 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
046 import org.jetbrains.jet.lang.types.JetType;
047
048 import java.util.Collection;
049 import java.util.Collections;
050 import java.util.List;
051
052 /**
053 * CallTransformer treats specially 'variable as function' call case, other cases keeps unchanged (base realization).
054 *
055 * For the call 'b.foo(1)' where foo is a variable that has method 'invoke' (for example of function type)
056 * CallTransformer creates two contexts, two calls in each, and performs second ('invoke') call resolution:
057 *
058 * context#1. calls: 'b.foo' 'invoke(1)'
059 * context#2. calls: 'foo' 'b.invoke(1)'
060 *
061 * If success VariableAsFunctionResolvedCall is created.
062 */
063 public class CallTransformer<D extends CallableDescriptor, F extends D> {
064 private CallTransformer() {}
065
066 /**
067 * Returns two contexts for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER), one context otherwise
068 */
069 @NotNull
070 public Collection<CallCandidateResolutionContext<D>> createCallContexts(@NotNull ResolutionCandidate<D> candidate,
071 @NotNull ResolutionTask<D, F> task,
072 @NotNull TemporaryBindingTrace candidateTrace
073 ) {
074 ResolvedCallImpl<D> candidateCall = ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments);
075 return Collections.singleton(CallCandidateResolutionContext.create(candidateCall, task, candidateTrace, task.tracing));
076 }
077
078 /**
079 * Returns collection of resolved calls for 'invoke' for 'variable as function' case (in FUNCTION_CALL_TRANSFORMER),
080 * the resolved call from callCandidateResolutionContext otherwise
081 */
082 @NotNull
083 public Collection<ResolvedCallWithTrace<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
084 @NotNull CallResolver callResolver,
085 @NotNull ResolutionTask<D, F> task
086 ) {
087 return Collections.singleton((ResolvedCallWithTrace<F>) callCandidateResolutionContext.candidateCall);
088 }
089
090
091 public static CallTransformer<VariableDescriptor, VariableDescriptor> PROPERTY_CALL_TRANSFORMER = new CallTransformer<VariableDescriptor, VariableDescriptor>();
092
093 public static CallTransformer<CallableDescriptor, FunctionDescriptor> FUNCTION_CALL_TRANSFORMER = new CallTransformer<CallableDescriptor, FunctionDescriptor>() {
094 @NotNull
095 @Override
096 public Collection<CallCandidateResolutionContext<CallableDescriptor>> createCallContexts(@NotNull ResolutionCandidate<CallableDescriptor> candidate,
097 @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task, @NotNull TemporaryBindingTrace candidateTrace) {
098
099 if (candidate.getDescriptor() instanceof FunctionDescriptor) {
100 return super.createCallContexts(candidate, task, candidateTrace);
101 }
102
103 assert candidate.getDescriptor() instanceof VariableDescriptor;
104
105 boolean hasReceiver = candidate.getReceiverArgument().exists();
106 Call variableCall = stripCallArguments(task);
107 if (!hasReceiver) {
108 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
109 ResolvedCallImpl.create(candidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments), task, candidateTrace, task.tracing, variableCall);
110 return Collections.singleton(context);
111 }
112 Call variableCallWithoutReceiver = stripReceiver(variableCall);
113 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
114 candidate, variableCall, candidateTrace, task);
115
116 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
117 candidate.getDescriptor(), candidate.getThisObject(), ReceiverValue.NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
118
119 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
120 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task);
121
122 contextWithoutReceiver.receiverForVariableAsFunctionSecondCall = variableCall.getExplicitReceiver();
123
124 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
125 }
126
127 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(ResolutionCandidate<CallableDescriptor> candidate,
128 Call call, TemporaryBindingTrace temporaryTrace, ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
129
130 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
131 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing, task.dataFlowInfoForArguments);
132 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call);
133 }
134
135 private Call stripCallArguments(@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
136 return new DelegatingCall(task.call) {
137 @Override
138 public JetValueArgumentList getValueArgumentList() {
139 return null;
140 }
141
142 @NotNull
143 @Override
144 public List<? extends ValueArgument> getValueArguments() {
145 return Collections.emptyList();
146 }
147
148 @NotNull
149 @Override
150 public List<JetExpression> getFunctionLiteralArguments() {
151 return Collections.emptyList();
152 }
153
154 @NotNull
155 @Override
156 public List<JetTypeProjection> getTypeArguments() {
157 return Collections.emptyList();
158 }
159
160 @Override
161 public JetTypeArgumentList getTypeArgumentList() {
162 return null;
163 }
164 };
165 }
166
167 private Call stripReceiver(@NotNull Call variableCall) {
168 return new DelegatingCall(variableCall) {
169 @NotNull
170 @Override
171 public ReceiverValue getExplicitReceiver() {
172 return ReceiverValue.NO_RECEIVER;
173 }
174 };
175 }
176
177 @NotNull
178 @Override
179 public Collection<ResolvedCallWithTrace<FunctionDescriptor>> transformCall(@NotNull CallCandidateResolutionContext<CallableDescriptor> context,
180 @NotNull CallResolver callResolver, @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
181
182 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
183 if (descriptor instanceof FunctionDescriptor) {
184 return super.transformCall(context, callResolver, task);
185 }
186
187 assert descriptor instanceof VariableDescriptor;
188 JetType returnType = descriptor.getReturnType();
189 if (returnType == null) {
190 return Collections.emptyList();
191 }
192
193 final ResolvedCallWithTrace<VariableDescriptor> variableResolvedCall = (ResolvedCallWithTrace)context.candidateCall;
194
195 Call functionCall = new CallForImplicitInvoke(context.receiverForVariableAsFunctionSecondCall, task, returnType);
196
197 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
198 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
199 context.replaceBindingTrace(variableCallTrace).replaceContextDependency(ContextDependency.DEPENDENT),
200 functionCall, context.checkArguments, context.dataFlowInfoForArguments);
201
202 // 'invoke' call resolve
203 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithGivenName(basicCallResolutionContext, task.reference, Name.identifier("invoke"));
204 Collection<ResolvedCallWithTrace<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
205
206 return Collections2.transform(calls, new Function<ResolvedCallWithTrace<FunctionDescriptor>, ResolvedCallWithTrace<FunctionDescriptor>>() {
207 @Override
208 public ResolvedCallWithTrace<FunctionDescriptor> apply(ResolvedCallWithTrace<FunctionDescriptor> functionResolvedCall) {
209 return new VariableAsFunctionResolvedCall(functionResolvedCall, variableResolvedCall);
210 }
211 });
212 }
213 };
214
215 public static class CallForImplicitInvoke extends DelegatingCall {
216 final Call outerCall;
217 final ReceiverValue receiverForVariableAsFunctionSecondCall;
218 final ExpressionReceiver receiverFromVariable;
219 final JetSimpleNameExpression invokeExpression;
220
221 private CallForImplicitInvoke(ReceiverValue receiverForVariableAsFunctionSecondCall,
222 ResolutionTask<CallableDescriptor, FunctionDescriptor> task, JetType returnType) {
223 super(task.call);
224 this.outerCall = task.call;
225 this.receiverForVariableAsFunctionSecondCall = receiverForVariableAsFunctionSecondCall;
226 this.receiverFromVariable = new ExpressionReceiver(task.reference, returnType);
227 this.invokeExpression = (JetSimpleNameExpression) JetPsiFactory.createExpression(task.call.getCallElement().getProject(), "invoke");
228 }
229 @NotNull
230 @Override
231 public ReceiverValue getExplicitReceiver() {
232 return receiverForVariableAsFunctionSecondCall;
233 }
234
235 @NotNull
236 @Override
237 public ReceiverValue getThisObject() {
238 return receiverFromVariable;
239 }
240
241 @Override
242 public JetExpression getCalleeExpression() {
243 return invokeExpression;
244 }
245
246 @NotNull
247 @Override
248 public PsiElement getCallElement() {
249 if (outerCall.getCallElement() instanceof JetCallElement) {
250 //to report errors properly
251 JetValueArgumentList list = ((JetCallElement)outerCall.getCallElement()).getValueArgumentList();
252 if (list != null) {
253 return list;
254 }
255 }
256 return invokeExpression;
257 }
258
259 @NotNull
260 @Override
261 public CallType getCallType() {
262 return CallType.INVOKE;
263 }
264
265 @NotNull
266 public Call getOuterCall() {
267 return outerCall;
268 }
269 }
270 }