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