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