001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.calls.model;
018    
019    import com.google.common.collect.Maps;
020    import com.intellij.openapi.diagnostic.Logger;
021    import com.intellij.util.Function;
022    import com.intellij.util.SmartList;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.descriptors.CallableDescriptor;
026    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
027    import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
028    import org.jetbrains.kotlin.psi.Call;
029    import org.jetbrains.kotlin.psi.ValueArgument;
030    import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
031    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
032    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
033    import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
034    import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus;
035    import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
036    import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
037    import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
038    import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
039    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
040    import org.jetbrains.kotlin.types.KotlinType;
041    import org.jetbrains.kotlin.types.TypeProjection;
042    import org.jetbrains.kotlin.types.TypeSubstitutor;
043    
044    import java.util.*;
045    
046    import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE;
047    import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS;
048    
049    public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableResolvedCall<D> {
050        private static final Logger LOG = Logger.getInstance(ResolvedCallImpl.class);
051    
052        public static final Function<MutableResolvedCall<?>, CallableDescriptor> MAP_TO_CANDIDATE = new Function<MutableResolvedCall<?>, CallableDescriptor>() {
053            @Override
054            public CallableDescriptor fun(MutableResolvedCall<?> resolvedCall) {
055                return resolvedCall.getCandidateDescriptor();
056            }
057        };
058    
059        public static final Function<MutableResolvedCall<?>, CallableDescriptor> MAP_TO_RESULT = new Function<MutableResolvedCall<?>, CallableDescriptor>() {
060            @Override
061            public CallableDescriptor fun(MutableResolvedCall<?> resolvedCall) {
062                return resolvedCall.getResultingDescriptor();
063            }
064        };
065    
066        @NotNull
067        public static <D extends CallableDescriptor> ResolvedCallImpl<D> create(
068                @NotNull ResolutionCandidate<D> candidate,
069                @NotNull DelegatingBindingTrace trace,
070                @NotNull TracingStrategy tracing,
071                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
072        ) {
073            return new ResolvedCallImpl<D>(candidate, trace, tracing, dataFlowInfoForArguments);
074        }
075    
076        private final Call call;
077        private final D candidateDescriptor;
078        private D resultingDescriptor; // Probably substituted
079        private final ReceiverValue dispatchReceiver; // receiver object of a method
080        private final Receiver extensionReceiver; // receiver of an extension function
081        private final ExplicitReceiverKind explicitReceiverKind;
082        private final TypeSubstitutor knownTypeParametersSubstitutor;
083    
084        @NotNull
085        private final Map<TypeParameterDescriptor, KotlinType> typeArguments;
086        @NotNull
087        private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments;
088        private final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
089        @NotNull
090        private final Map<ValueArgument, ArgumentMatchImpl> argumentToParameterMap;
091    
092        private DelegatingBindingTrace trace;
093        private TracingStrategy tracing;
094        private ResolutionStatus status = UNKNOWN_STATUS;
095        private ConstraintSystem constraintSystem = null;
096        private Boolean hasInferredReturnType = null;
097        private boolean completed = false;
098        private KotlinType smartCastDispatchReceiverType = null;
099    
100        private ResolvedCallImpl(
101                @NotNull ResolutionCandidate<D> candidate,
102                @NotNull DelegatingBindingTrace trace,
103                @NotNull TracingStrategy tracing,
104                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
105        ) {
106            this.call = candidate.getCall();
107            this.candidateDescriptor = candidate.getDescriptor();
108            this.dispatchReceiver = candidate.getDispatchReceiver();
109            this.extensionReceiver = candidate.getReceiverArgument();
110            this.explicitReceiverKind = candidate.getExplicitReceiverKind();
111            this.knownTypeParametersSubstitutor = candidate.getKnownTypeParametersResultingSubstitutor();
112            this.trace = trace;
113            this.tracing = tracing;
114            this.dataFlowInfoForArguments = dataFlowInfoForArguments;
115            this.typeArguments = createTypeArgumentsMap(candidateDescriptor);
116            this.valueArguments = createValueArgumentsMap(candidateDescriptor);
117            this.argumentToParameterMap = createArgumentsToParameterMap(candidateDescriptor);
118        }
119    
120        public ResolvedCallImpl(
121                @NotNull Call call,
122                @NotNull D candidateDescriptor,
123                @Nullable ReceiverValue dispatchReceiver,
124                @Nullable ReceiverValue extensionReceiver,
125                @NotNull ExplicitReceiverKind explicitReceiverKind,
126                @Nullable TypeSubstitutor knownTypeParametersSubstitutor,
127                @NotNull DelegatingBindingTrace trace,
128                @NotNull TracingStrategy tracing,
129                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
130        ) {
131            this.call = call;
132            this.candidateDescriptor = candidateDescriptor;
133            this.dispatchReceiver = dispatchReceiver;
134            this.extensionReceiver = extensionReceiver;
135            this.explicitReceiverKind = explicitReceiverKind;
136            this.knownTypeParametersSubstitutor = knownTypeParametersSubstitutor;
137            this.trace = trace;
138            this.tracing = tracing;
139            this.dataFlowInfoForArguments = dataFlowInfoForArguments;
140            this.typeArguments = createTypeArgumentsMap(candidateDescriptor);
141            this.valueArguments = createValueArgumentsMap(candidateDescriptor);
142            this.argumentToParameterMap = createArgumentsToParameterMap(candidateDescriptor);
143        }
144    
145        @NotNull
146        private static Map<ValueParameterDescriptor, ResolvedValueArgument> createValueArgumentsMap(CallableDescriptor descriptor) {
147            return descriptor.getValueParameters().isEmpty()
148                   ? Collections.<ValueParameterDescriptor, ResolvedValueArgument>emptyMap()
149                   : Maps.<ValueParameterDescriptor, ResolvedValueArgument>newLinkedHashMap();
150        }
151    
152        @NotNull
153        private static Map<ValueArgument, ArgumentMatchImpl> createArgumentsToParameterMap(CallableDescriptor descriptor) {
154            return descriptor.getValueParameters().isEmpty()
155                   ? Collections.<ValueArgument, ArgumentMatchImpl>emptyMap()
156                   : Maps.<ValueArgument, ArgumentMatchImpl>newHashMap();
157        }
158    
159        @NotNull
160        private static Map<TypeParameterDescriptor, KotlinType> createTypeArgumentsMap(CallableDescriptor descriptor) {
161            return descriptor.getTypeParameters().isEmpty()
162                   ? Collections.<TypeParameterDescriptor, KotlinType>emptyMap()
163                   : Maps.<TypeParameterDescriptor, KotlinType>newLinkedHashMap();
164        }
165    
166        @Override
167        @NotNull
168        public ResolutionStatus getStatus() {
169            return status;
170        }
171    
172        @Override
173        public void addStatus(@NotNull ResolutionStatus status) {
174            this.status = this.status.combine(status);
175        }
176    
177        @Override
178        public void setStatusToSuccess() {
179            assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
180            status = ResolutionStatus.SUCCESS;
181        }
182    
183        @Override
184        @NotNull
185        public DelegatingBindingTrace getTrace() {
186            assertNotCompleted("Trace");
187            return trace;
188        }
189    
190        @Override
191        @NotNull
192        public TracingStrategy getTracingStrategy() {
193            assertNotCompleted("TracingStrategy");
194            return tracing;
195        }
196    
197        @NotNull
198        @Override
199        public Call getCall() {
200            return call;
201        }
202    
203        @Override
204        @NotNull
205        public D getCandidateDescriptor() {
206            return candidateDescriptor;
207        }
208    
209        @Override
210        @NotNull
211        public D getResultingDescriptor() {
212            return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
213        }
214    
215        @Override
216        public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
217            resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
218            assert resultingDescriptor != null : candidateDescriptor;
219    
220            for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
221                TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getDefaultType());
222                if (typeArgumentProjection != null) {
223                    typeArguments.put(typeParameter, typeArgumentProjection.getType());
224                }
225            }
226    
227            if (candidateDescriptor.getValueParameters().isEmpty()) return;
228    
229            List<ValueParameterDescriptor> substitutedParameters = resultingDescriptor.getValueParameters();
230    
231            Collection<Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>> valueArgumentsBeforeSubstitution =
232                    new SmartList<Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>>(valueArguments.entrySet());
233    
234            valueArguments.clear();
235    
236            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArgumentsBeforeSubstitution) {
237                ValueParameterDescriptor substitutedVersion = substitutedParameters.get(entry.getKey().getIndex());
238                assert substitutedVersion != null : entry.getKey();
239                valueArguments.put(substitutedVersion, entry.getValue());
240            }
241    
242            Collection<Map.Entry<ValueArgument, ArgumentMatchImpl>> unsubstitutedArgumentMappings =
243                    new SmartList<Map.Entry<ValueArgument, ArgumentMatchImpl>>(argumentToParameterMap.entrySet());
244    
245            argumentToParameterMap.clear();
246            for (Map.Entry<ValueArgument, ArgumentMatchImpl> entry : unsubstitutedArgumentMappings) {
247                ArgumentMatchImpl argumentMatch = entry.getValue();
248                ValueParameterDescriptor valueParameterDescriptor = argumentMatch.getValueParameter();
249                ValueParameterDescriptor substitutedVersion = substitutedParameters.get(valueParameterDescriptor.getIndex());
250                assert substitutedVersion != null : valueParameterDescriptor;
251                argumentToParameterMap.put(entry.getKey(), argumentMatch.replaceValueParameter(substitutedVersion));
252            }
253        }
254    
255        @Override
256        public void setConstraintSystem(@NotNull ConstraintSystem constraintSystem) {
257            this.constraintSystem = constraintSystem;
258        }
259    
260        @Nullable
261        @Override
262        public ConstraintSystem getConstraintSystem() {
263            assertNotCompleted("ConstraintSystem");
264            return constraintSystem;
265        }
266    
267        @Override
268        public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
269            assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
270            valueArguments.put(valueParameter, valueArgument);
271            for (ValueArgument argument : valueArgument.getArguments()) {
272                argumentToParameterMap.put(argument, new ArgumentMatchImpl(valueParameter));
273            }
274        }
275    
276        @Override
277        @Nullable
278        public Receiver getExtensionReceiver() {
279            return extensionReceiver;
280        }
281    
282        @Override
283        @Nullable
284        public ReceiverValue getDispatchReceiver() {
285            return dispatchReceiver;
286        }
287    
288        @Override
289        @NotNull
290        public ExplicitReceiverKind getExplicitReceiverKind() {
291            return explicitReceiverKind;
292        }
293    
294        @Override
295        @NotNull
296        public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
297            return valueArguments;
298        }
299    
300        @Nullable
301        @Override
302        public List<ResolvedValueArgument> getValueArgumentsByIndex() {
303            List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
304            for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
305                arguments.add(null);
306            }
307            
308            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
309                ValueParameterDescriptor parameterDescriptor = entry.getKey();
310                ResolvedValueArgument value = entry.getValue();
311                ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
312                if (oldValue != null) {
313                    return null;
314                }
315            }
316    
317            for (int i = 0; i < arguments.size(); i++) {
318                Object o = arguments.get(i);
319                if (o == null) {
320                    return null;
321                }
322            }
323            
324            return arguments;
325        }
326    
327        @Override
328        public void recordArgumentMatchStatus(@NotNull ValueArgument valueArgument, @NotNull ArgumentMatchStatus matchStatus) {
329            ArgumentMatchImpl argumentMatch = argumentToParameterMap.get(valueArgument);
330            argumentMatch.recordMatchStatus(matchStatus);
331        }
332    
333        @NotNull
334        @Override
335        public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) {
336            ArgumentMatch argumentMatch = argumentToParameterMap.get(valueArgument);
337            if (argumentMatch == null) {
338                if (ArgumentMappingKt.isReallySuccess(this)) {
339                    LOG.error("ArgumentUnmapped for " + valueArgument + " in successfully resolved call: " + call.getCallElement().getText());
340                }
341                return ArgumentUnmapped.INSTANCE;
342            }
343            return argumentMatch;
344        }
345    
346        @NotNull
347        @Override
348        public Map<TypeParameterDescriptor, KotlinType> getTypeArguments() {
349            return typeArguments;
350        }
351    
352        @Override
353        public boolean isSafeCall() {
354            return CallUtilKt.isSafeCall(call);
355        }
356    
357        @NotNull
358        @Override
359        public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
360            return dataFlowInfoForArguments;
361        }
362    
363        @Override
364        public boolean hasInferredReturnType() {
365            if (!completed) {
366                hasInferredReturnType = constraintSystem == null ||
367                                        CallResolverUtilKt.hasInferredReturnType(candidateDescriptor, constraintSystem);
368            }
369            assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
370            return hasInferredReturnType;
371        }
372    
373        @Override
374        public void markCallAsCompleted() {
375            if (!completed) {
376                hasInferredReturnType();
377            }
378            trace = null;
379            constraintSystem = null;
380            tracing = null;
381            completed = true;
382        }
383    
384        @Override
385        public boolean isCompleted() {
386            return completed;
387        }
388    
389        private void assertNotCompleted(String elementName) {
390            assert !completed: elementName + " is erased after resolution completion.";
391        }
392    
393        @Override
394        @Nullable
395        public TypeSubstitutor getKnownTypeParametersSubstitutor() {
396            return knownTypeParametersSubstitutor;
397        }
398    
399        @Override
400        public void setSmartCastDispatchReceiverType(@NotNull KotlinType smartCastDispatchReceiverType) {
401            this.smartCastDispatchReceiverType = smartCastDispatchReceiverType;
402        }
403    
404        @Override
405        @Nullable
406        public KotlinType getSmartCastDispatchReceiverType() {
407            return smartCastDispatchReceiverType;
408        }
409    }