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.model.ResolvedCallImpl;
034 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
035 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
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.util.DelegatingCall;
042 import org.jetbrains.jet.lang.resolve.name.Name;
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);
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<ResolvedCallWithTrace<F>> transformCall(@NotNull CallCandidateResolutionContext<D> callCandidateResolutionContext,
083 @NotNull CallResolver callResolver,
084 @NotNull ResolutionTask<D, F> task) {
085
086 return Collections.singleton((ResolvedCallWithTrace<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);
106 if (!hasReceiver) {
107 CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
108 ResolvedCallImpl.create(candidate, candidateTrace, task.tracing), task, candidateTrace, task.tracing, variableCall);
109 return Collections.singleton(context);
110 }
111 Call variableCallWithoutReceiver = stripReceiver(variableCall);
112 CallCandidateResolutionContext<CallableDescriptor> contextWithReceiver = createContextWithChainedTrace(
113 candidate, variableCall, candidateTrace, task);
114
115 ResolutionCandidate<CallableDescriptor> candidateWithoutReceiver = ResolutionCandidate.create(
116 candidate.getDescriptor(), candidate.getThisObject(), ReceiverValue.NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, false);
117
118 CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
119 candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task);
120
121 contextWithoutReceiver.receiverForVariableAsFunctionSecondCall = variableCall.getExplicitReceiver();
122
123 return Lists.newArrayList(contextWithReceiver, contextWithoutReceiver);
124 }
125
126 private CallCandidateResolutionContext<CallableDescriptor> createContextWithChainedTrace(ResolutionCandidate<CallableDescriptor> candidate,
127 Call call, TemporaryBindingTrace temporaryTrace, ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
128
129 ChainedTemporaryBindingTrace chainedTrace = ChainedTemporaryBindingTrace.create(temporaryTrace, "chained trace to resolve candidate", candidate);
130 ResolvedCallImpl<CallableDescriptor> resolvedCall = ResolvedCallImpl.create(candidate, chainedTrace, task.tracing);
131 return CallCandidateResolutionContext.create(resolvedCall, task, chainedTrace, task.tracing, call);
132 }
133
134 private Call stripCallArguments(@NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
135 return new DelegatingCall(task.call) {
136 @Override
137 public JetValueArgumentList getValueArgumentList() {
138 return null;
139 }
140
141 @NotNull
142 @Override
143 public List<? extends ValueArgument> getValueArguments() {
144 return Collections.emptyList();
145 }
146
147 @NotNull
148 @Override
149 public List<JetExpression> getFunctionLiteralArguments() {
150 return Collections.emptyList();
151 }
152
153 @NotNull
154 @Override
155 public List<JetTypeProjection> getTypeArguments() {
156 return Collections.emptyList();
157 }
158
159 @Override
160 public JetTypeArgumentList getTypeArgumentList() {
161 return null;
162 }
163 };
164 }
165
166 private Call stripReceiver(@NotNull Call variableCall) {
167 return new DelegatingCall(variableCall) {
168 @NotNull
169 @Override
170 public ReceiverValue getExplicitReceiver() {
171 return ReceiverValue.NO_RECEIVER;
172 }
173 };
174 }
175
176 @NotNull
177 @Override
178 public Collection<ResolvedCallWithTrace<FunctionDescriptor>> transformCall(@NotNull CallCandidateResolutionContext<CallableDescriptor> context,
179 @NotNull CallResolver callResolver, @NotNull ResolutionTask<CallableDescriptor, FunctionDescriptor> task) {
180
181 CallableDescriptor descriptor = context.candidateCall.getCandidateDescriptor();
182 if (descriptor instanceof FunctionDescriptor) {
183 return super.transformCall(context, callResolver, task);
184 }
185
186 assert descriptor instanceof VariableDescriptor;
187 JetType returnType = descriptor.getReturnType();
188 if (returnType == null) {
189 return Collections.emptyList();
190 }
191
192 final ResolvedCallWithTrace<VariableDescriptor> variableResolvedCall = (ResolvedCallWithTrace)context.candidateCall;
193
194 Call functionCall = new CallForImplicitInvoke(context, task, returnType);
195
196 DelegatingBindingTrace variableCallTrace = context.candidateCall.getTrace();
197 BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
198 variableCallTrace, context.scope, functionCall, context.expectedType, context.dataFlowInfo,
199 context.resolveMode, context.checkArguments, context.expressionPosition, context.resolutionResultsCache);
200
201 // 'invoke' call resolve
202 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithGivenName(basicCallResolutionContext, task.reference, Name.identifier("invoke"));
203 Collection<ResolvedCallWithTrace<FunctionDescriptor>> calls = ((OverloadResolutionResultsImpl<FunctionDescriptor>)results).getResultingCalls();
204
205 return Collections2.transform(calls, new Function<ResolvedCallWithTrace<FunctionDescriptor>, ResolvedCallWithTrace<FunctionDescriptor>>() {
206 @Override
207 public ResolvedCallWithTrace<FunctionDescriptor> apply(ResolvedCallWithTrace<FunctionDescriptor> functionResolvedCall) {
208 return new VariableAsFunctionResolvedCall(functionResolvedCall, variableResolvedCall);
209 }
210 });
211 }
212 };
213
214 public static class CallForImplicitInvoke extends DelegatingCall {
215 final Call outerCall;
216 final CallCandidateResolutionContext<CallableDescriptor> context;
217 final ExpressionReceiver receiverFromVariable;
218 final JetSimpleNameExpression invokeExpression;
219
220 private CallForImplicitInvoke(CallCandidateResolutionContext<CallableDescriptor> context,
221 ResolutionTask<CallableDescriptor, FunctionDescriptor> task, JetType returnType) {
222 super(task.call);
223 this.outerCall = task.call;
224 this.context = context;
225 this.receiverFromVariable = new ExpressionReceiver(task.reference, returnType);
226 this.invokeExpression = (JetSimpleNameExpression) JetPsiFactory.createExpression(task.call.getCallElement().getProject(), "invoke");
227 }
228 @NotNull
229 @Override
230 public ReceiverValue getExplicitReceiver() {
231 return context.receiverForVariableAsFunctionSecondCall;
232 }
233
234 @NotNull
235 @Override
236 public ReceiverValue getThisObject() {
237 return receiverFromVariable;
238 }
239
240 @Override
241 public JetExpression getCalleeExpression() {
242 return invokeExpression;
243 }
244
245 @NotNull
246 @Override
247 public PsiElement getCallElement() {
248 if (outerCall.getCallElement() instanceof JetCallElement) {
249 //to report errors properly
250 JetValueArgumentList list = ((JetCallElement)outerCall.getCallElement()).getValueArgumentList();
251 if (list != null) {
252 return list;
253 }
254 }
255 return invokeExpression;
256 }
257
258 @NotNull
259 @Override
260 public CallType getCallType() {
261 return CallType.INVOKE;
262 }
263
264 @NotNull
265 public Call getOuterCall() {
266 return outerCall;
267 }
268 }
269 }