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    }