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 }