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        @Override
114        @NotNull
115        public ResolutionStatus getStatus() {
116            return status;
117        }
118    
119        @Override
120        public void addStatus(@NotNull ResolutionStatus status) {
121            this.status = this.status.combine(status);
122        }
123    
124        @Override
125        public void setStatusToSuccess() {
126            assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
127            status = ResolutionStatus.SUCCESS;
128        }
129    
130        @Override
131        @NotNull
132        public DelegatingBindingTrace getTrace() {
133            assertNotCompleted("Trace");
134            return trace;
135        }
136    
137        @NotNull
138        public TracingStrategy getTracing() {
139            assertNotCompleted("TracingStrategy");
140            return tracing;
141        }
142    
143        @NotNull
144        @Override
145        public Call getCall() {
146            return call;
147        }
148    
149        @Override
150        @NotNull
151        public D getCandidateDescriptor() {
152            return candidateDescriptor;
153        }
154    
155        @Override
156        @NotNull
157        public D getResultingDescriptor() {
158            return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
159        }
160    
161        @Override
162        public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
163            resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
164            assert resultingDescriptor != null : candidateDescriptor;
165    
166            for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
167                TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getDefaultType());
168                if (typeArgumentProjection != null) {
169                    typeArguments.put(typeParameter, typeArgumentProjection.getType());
170                }
171            }
172    
173            Map<ValueParameterDescriptor, ValueParameterDescriptor> substitutedParametersMap = Maps.newHashMap();
174            for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
175                substitutedParametersMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
176            }
177    
178            Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newLinkedHashMap(valueArguments);
179            valueArguments.clear();
180            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
181                ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(entry.getKey().getOriginal());
182                assert substitutedVersion != null : entry.getKey();
183                valueArguments.put(substitutedVersion, entry.getValue());
184            }
185    
186            Map<ValueArgument, ArgumentMatchImpl> originalArgumentToParameterMap = Maps.newLinkedHashMap(argumentToParameterMap);
187            argumentToParameterMap.clear();
188            for (Map.Entry<ValueArgument, ArgumentMatchImpl> entry : originalArgumentToParameterMap.entrySet()) {
189                ArgumentMatchImpl argumentMatch = entry.getValue();
190                ValueParameterDescriptor valueParameterDescriptor = argumentMatch.getValueParameter();
191                ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(valueParameterDescriptor.getOriginal());
192                assert substitutedVersion != null : valueParameterDescriptor;
193                argumentToParameterMap.put(entry.getKey(), argumentMatch.replaceValueParameter(substitutedVersion));
194            }
195        }
196    
197        @Override
198        public void setConstraintSystem(@NotNull ConstraintSystem constraintSystem) {
199            this.constraintSystem = constraintSystem;
200        }
201    
202        @Nullable
203        @Override
204        public ConstraintSystem getConstraintSystem() {
205            assertNotCompleted("ConstraintSystem");
206            return constraintSystem;
207        }
208    
209        @Override
210        public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
211            assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
212            valueArguments.put(valueParameter, valueArgument);
213            for (ValueArgument argument : valueArgument.getArguments()) {
214                argumentToParameterMap.put(argument, new ArgumentMatchImpl(valueParameter));
215            }
216        }
217    
218        @Override
219        @NotNull
220        public ReceiverValue getExtensionReceiver() {
221            return extensionReceiver;
222        }
223    
224        @Override
225        @NotNull
226        public ReceiverValue getDispatchReceiver() {
227            return dispatchReceiver;
228        }
229    
230        @Override
231        @NotNull
232        public ExplicitReceiverKind getExplicitReceiverKind() {
233            return explicitReceiverKind;
234        }
235    
236        @Override
237        @NotNull
238        public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
239            return valueArguments;
240        }
241    
242        @Nullable
243        @Override
244        public List<ResolvedValueArgument> getValueArgumentsByIndex() {
245            List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
246            for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
247                arguments.add(null);
248            }
249            
250            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
251                ValueParameterDescriptor parameterDescriptor = entry.getKey();
252                ResolvedValueArgument value = entry.getValue();
253                ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
254                if (oldValue != null) {
255                    return null;
256                }
257            }
258    
259            for (int i = 0; i < arguments.size(); i++) {
260                Object o = arguments.get(i);
261                if (o == null) {
262                    return null;
263                }
264            }
265            
266            return arguments;
267        }
268    
269        @Override
270        public void recordArgumentMatchStatus(@NotNull ValueArgument valueArgument, @NotNull ArgumentMatchStatus matchStatus) {
271            ArgumentMatchImpl argumentMatch = argumentToParameterMap.get(valueArgument);
272            argumentMatch.recordMatchStatus(matchStatus);
273        }
274    
275        @NotNull
276        @Override
277        public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) {
278            ArgumentMatch argumentMatch = argumentToParameterMap.get(valueArgument);
279            if (argumentMatch == null) {
280                if (ArgumentMappingKt.isReallySuccess(this)) {
281                    LOG.error("ArgumentUnmapped for " + valueArgument + " in successfully resolved call: " + call.getCallElement().getText());
282                }
283                return ArgumentUnmapped.INSTANCE$;
284            }
285            return argumentMatch;
286        }
287    
288        @NotNull
289        @Override
290        public Map<TypeParameterDescriptor, KotlinType> getTypeArguments() {
291            return typeArguments;
292        }
293    
294        @Override
295        public boolean isSafeCall() {
296            return CallUtilKt.isSafeCall(call);
297        }
298    
299        @NotNull
300        @Override
301        public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
302            return dataFlowInfoForArguments;
303        }
304    
305        @Override
306        public boolean hasInferredReturnType() {
307            if (!completed) {
308                hasInferredReturnType = constraintSystem == null ||
309                                        CallResolverUtilKt.hasInferredReturnType(candidateDescriptor, constraintSystem);
310            }
311            assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
312            return hasInferredReturnType;
313        }
314    
315        @Override
316        public void markCallAsCompleted() {
317            if (!completed) {
318                hasInferredReturnType();
319            }
320            trace = null;
321            constraintSystem = null;
322            tracing = null;
323            completed = true;
324        }
325    
326        @Override
327        public boolean isCompleted() {
328            return completed;
329        }
330    
331        private void assertNotCompleted(String elementName) {
332            assert !completed: elementName + " is erased after resolution completion.";
333        }
334    
335        @Override
336        @Nullable
337        public TypeSubstitutor getKnownTypeParametersSubstitutor() {
338            return knownTypeParametersSubstitutor;
339        }
340    }