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 org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.descriptors.CallableDescriptor;
025    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
026    import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
027    import org.jetbrains.kotlin.psi.Call;
028    import org.jetbrains.kotlin.psi.ValueArgument;
029    import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
030    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
031    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
032    import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
033    import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus;
034    import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
035    import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
036    import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
037    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
038    import org.jetbrains.kotlin.types.KotlinType;
039    import org.jetbrains.kotlin.types.TypeProjection;
040    import org.jetbrains.kotlin.types.TypeSubstitutor;
041    
042    import java.util.ArrayList;
043    import java.util.List;
044    import java.util.Map;
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 ReceiverValue extensionReceiver; // receiver of an extension function
081        private final ExplicitReceiverKind explicitReceiverKind;
082        private final TypeSubstitutor knownTypeParametersSubstitutor;
083    
084        private final Map<TypeParameterDescriptor, KotlinType> typeArguments = Maps.newLinkedHashMap();
085        private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
086        private final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
087        private final Map<ValueArgument, ArgumentMatchImpl> argumentToParameterMap = Maps.newHashMap();
088    
089        private DelegatingBindingTrace trace;
090        private TracingStrategy tracing;
091        private ResolutionStatus status = UNKNOWN_STATUS;
092        private ConstraintSystem constraintSystem = null;
093        private Boolean hasInferredReturnType = null;
094        private boolean completed = false;
095    
096        private ResolvedCallImpl(
097                @NotNull ResolutionCandidate<D> candidate,
098                @NotNull DelegatingBindingTrace trace,
099                @NotNull TracingStrategy tracing,
100                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
101        ) {
102            this.call = candidate.getCall();
103            this.candidateDescriptor = candidate.getDescriptor();
104            this.dispatchReceiver = candidate.getDispatchReceiver();
105            this.extensionReceiver = candidate.getExtensionReceiver();
106            this.explicitReceiverKind = candidate.getExplicitReceiverKind();
107            this.knownTypeParametersSubstitutor = candidate.getKnownTypeParametersResultingSubstitutor();
108            this.trace = trace;
109            this.tracing = tracing;
110            this.dataFlowInfoForArguments = dataFlowInfoForArguments;
111        }
112    
113        public ResolvedCallImpl(
114                @NotNull Call call,
115                @NotNull D candidateDescriptor,
116                @NotNull ReceiverValue dispatchReceiver,
117                @NotNull ReceiverValue extensionReceiver,
118                @NotNull ExplicitReceiverKind explicitReceiverKind,
119                @Nullable TypeSubstitutor knownTypeParametersSubstitutor,
120                @NotNull DelegatingBindingTrace trace,
121                @NotNull TracingStrategy tracing,
122                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
123        ) {
124            this.call = call;
125            this.candidateDescriptor = candidateDescriptor;
126            this.dispatchReceiver = dispatchReceiver;
127            this.extensionReceiver = extensionReceiver;
128            this.explicitReceiverKind = explicitReceiverKind;
129            this.knownTypeParametersSubstitutor = knownTypeParametersSubstitutor;
130            this.trace = trace;
131            this.tracing = tracing;
132            this.dataFlowInfoForArguments = dataFlowInfoForArguments;
133        }
134    
135        @Override
136        @NotNull
137        public ResolutionStatus getStatus() {
138            return status;
139        }
140    
141        @Override
142        public void addStatus(@NotNull ResolutionStatus status) {
143            this.status = this.status.combine(status);
144        }
145    
146        @Override
147        public void setStatusToSuccess() {
148            assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
149            status = ResolutionStatus.SUCCESS;
150        }
151    
152        @Override
153        @NotNull
154        public DelegatingBindingTrace getTrace() {
155            assertNotCompleted("Trace");
156            return trace;
157        }
158    
159        @Override
160        @NotNull
161        public TracingStrategy getTracingStrategy() {
162            assertNotCompleted("TracingStrategy");
163            return tracing;
164        }
165    
166        @NotNull
167        @Override
168        public Call getCall() {
169            return call;
170        }
171    
172        @Override
173        @NotNull
174        public D getCandidateDescriptor() {
175            return candidateDescriptor;
176        }
177    
178        @Override
179        @NotNull
180        public D getResultingDescriptor() {
181            return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
182        }
183    
184        @Override
185        public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
186            resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
187            assert resultingDescriptor != null : candidateDescriptor;
188    
189            for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
190                TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getDefaultType());
191                if (typeArgumentProjection != null) {
192                    typeArguments.put(typeParameter, typeArgumentProjection.getType());
193                }
194            }
195    
196            Map<ValueParameterDescriptor, ValueParameterDescriptor> substitutedParametersMap = Maps.newHashMap();
197            for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
198                substitutedParametersMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
199            }
200    
201            Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newLinkedHashMap(valueArguments);
202            valueArguments.clear();
203            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
204                ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(entry.getKey().getOriginal());
205                assert substitutedVersion != null : entry.getKey();
206                valueArguments.put(substitutedVersion, entry.getValue());
207            }
208    
209            Map<ValueArgument, ArgumentMatchImpl> originalArgumentToParameterMap = Maps.newLinkedHashMap(argumentToParameterMap);
210            argumentToParameterMap.clear();
211            for (Map.Entry<ValueArgument, ArgumentMatchImpl> entry : originalArgumentToParameterMap.entrySet()) {
212                ArgumentMatchImpl argumentMatch = entry.getValue();
213                ValueParameterDescriptor valueParameterDescriptor = argumentMatch.getValueParameter();
214                ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(valueParameterDescriptor.getOriginal());
215                assert substitutedVersion != null : valueParameterDescriptor;
216                argumentToParameterMap.put(entry.getKey(), argumentMatch.replaceValueParameter(substitutedVersion));
217            }
218        }
219    
220        @Override
221        public void setConstraintSystem(@NotNull ConstraintSystem constraintSystem) {
222            this.constraintSystem = constraintSystem;
223        }
224    
225        @Nullable
226        @Override
227        public ConstraintSystem getConstraintSystem() {
228            assertNotCompleted("ConstraintSystem");
229            return constraintSystem;
230        }
231    
232        @Override
233        public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
234            assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
235            valueArguments.put(valueParameter, valueArgument);
236            for (ValueArgument argument : valueArgument.getArguments()) {
237                argumentToParameterMap.put(argument, new ArgumentMatchImpl(valueParameter));
238            }
239        }
240    
241        @Override
242        @NotNull
243        public ReceiverValue getExtensionReceiver() {
244            return extensionReceiver;
245        }
246    
247        @Override
248        @NotNull
249        public ReceiverValue getDispatchReceiver() {
250            return dispatchReceiver;
251        }
252    
253        @Override
254        @NotNull
255        public ExplicitReceiverKind getExplicitReceiverKind() {
256            return explicitReceiverKind;
257        }
258    
259        @Override
260        @NotNull
261        public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
262            return valueArguments;
263        }
264    
265        @Nullable
266        @Override
267        public List<ResolvedValueArgument> getValueArgumentsByIndex() {
268            List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
269            for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
270                arguments.add(null);
271            }
272            
273            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
274                ValueParameterDescriptor parameterDescriptor = entry.getKey();
275                ResolvedValueArgument value = entry.getValue();
276                ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
277                if (oldValue != null) {
278                    return null;
279                }
280            }
281    
282            for (int i = 0; i < arguments.size(); i++) {
283                Object o = arguments.get(i);
284                if (o == null) {
285                    return null;
286                }
287            }
288            
289            return arguments;
290        }
291    
292        @Override
293        public void recordArgumentMatchStatus(@NotNull ValueArgument valueArgument, @NotNull ArgumentMatchStatus matchStatus) {
294            ArgumentMatchImpl argumentMatch = argumentToParameterMap.get(valueArgument);
295            argumentMatch.recordMatchStatus(matchStatus);
296        }
297    
298        @NotNull
299        @Override
300        public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) {
301            ArgumentMatch argumentMatch = argumentToParameterMap.get(valueArgument);
302            if (argumentMatch == null) {
303                if (ArgumentMappingKt.isReallySuccess(this)) {
304                    LOG.error("ArgumentUnmapped for " + valueArgument + " in successfully resolved call: " + call.getCallElement().getText());
305                }
306                return ArgumentUnmapped.INSTANCE$;
307            }
308            return argumentMatch;
309        }
310    
311        @NotNull
312        @Override
313        public Map<TypeParameterDescriptor, KotlinType> getTypeArguments() {
314            return typeArguments;
315        }
316    
317        @Override
318        public boolean isSafeCall() {
319            return CallUtilKt.isSafeCall(call);
320        }
321    
322        @NotNull
323        @Override
324        public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
325            return dataFlowInfoForArguments;
326        }
327    
328        @Override
329        public boolean hasInferredReturnType() {
330            if (!completed) {
331                hasInferredReturnType = constraintSystem == null ||
332                                        CallResolverUtilKt.hasInferredReturnType(candidateDescriptor, constraintSystem);
333            }
334            assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
335            return hasInferredReturnType;
336        }
337    
338        @Override
339        public void markCallAsCompleted() {
340            if (!completed) {
341                hasInferredReturnType();
342            }
343            trace = null;
344            constraintSystem = null;
345            tracing = null;
346            completed = true;
347        }
348    
349        @Override
350        public boolean isCompleted() {
351            return completed;
352        }
353    
354        private void assertNotCompleted(String elementName) {
355            assert !completed: elementName + " is erased after resolution completion.";
356        }
357    
358        @Override
359        @Nullable
360        public TypeSubstitutor getKnownTypeParametersSubstitutor() {
361            return knownTypeParametersSubstitutor;
362        }
363    }