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