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