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 final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
088 private final Map<ValueArgument, ArgumentMatchImpl> argumentToParameterMap = Maps.newHashMap();
089
090 private DelegatingBindingTrace trace;
091 private TracingStrategy tracing;
092 private ResolutionStatus status = UNKNOWN_STATUS;
093 private ConstraintSystem constraintSystem = null;
094 private Boolean hasInferredReturnType = null;
095 private boolean completed = false;
096
097 private ResolvedCallImpl(
098 @NotNull ResolutionCandidate<D> candidate,
099 @NotNull DelegatingBindingTrace trace,
100 @NotNull TracingStrategy tracing,
101 @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
102 ) {
103 this.call = candidate.getCall();
104 this.candidateDescriptor = candidate.getDescriptor();
105 this.dispatchReceiver = candidate.getDispatchReceiver();
106 this.extensionReceiver = candidate.getReceiverArgument();
107 this.explicitReceiverKind = candidate.getExplicitReceiverKind();
108 this.knownTypeParametersSubstitutor = candidate.getKnownTypeParametersResultingSubstitutor();
109 this.trace = trace;
110 this.tracing = tracing;
111 this.dataFlowInfoForArguments = dataFlowInfoForArguments;
112 }
113
114 public ResolvedCallImpl(
115 @NotNull Call call,
116 @NotNull D candidateDescriptor,
117 @NotNull ReceiverValue dispatchReceiver,
118 @NotNull ReceiverValue extensionReceiver,
119 @NotNull ExplicitReceiverKind explicitReceiverKind,
120 @Nullable TypeSubstitutor knownTypeParametersSubstitutor,
121 @NotNull DelegatingBindingTrace trace,
122 @NotNull TracingStrategy tracing,
123 @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
124 ) {
125 this.call = call;
126 this.candidateDescriptor = candidateDescriptor;
127 this.dispatchReceiver = dispatchReceiver;
128 this.extensionReceiver = extensionReceiver;
129 this.explicitReceiverKind = explicitReceiverKind;
130 this.knownTypeParametersSubstitutor = knownTypeParametersSubstitutor;
131 this.trace = trace;
132 this.tracing = tracing;
133 this.dataFlowInfoForArguments = dataFlowInfoForArguments;
134 }
135
136 @Override
137 @NotNull
138 public ResolutionStatus getStatus() {
139 return status;
140 }
141
142 @Override
143 public void addStatus(@NotNull ResolutionStatus status) {
144 this.status = this.status.combine(status);
145 }
146
147 @Override
148 public void setStatusToSuccess() {
149 assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
150 status = ResolutionStatus.SUCCESS;
151 }
152
153 @Override
154 @NotNull
155 public DelegatingBindingTrace getTrace() {
156 assertNotCompleted("Trace");
157 return trace;
158 }
159
160 @Override
161 @NotNull
162 public TracingStrategy getTracingStrategy() {
163 assertNotCompleted("TracingStrategy");
164 return tracing;
165 }
166
167 @NotNull
168 @Override
169 public Call getCall() {
170 return call;
171 }
172
173 @Override
174 @NotNull
175 public D getCandidateDescriptor() {
176 return candidateDescriptor;
177 }
178
179 @Override
180 @NotNull
181 public D getResultingDescriptor() {
182 return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
183 }
184
185 @Override
186 public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
187 resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
188 assert resultingDescriptor != null : candidateDescriptor;
189
190 for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
191 TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getDefaultType());
192 if (typeArgumentProjection != null) {
193 typeArguments.put(typeParameter, typeArgumentProjection.getType());
194 }
195 }
196
197 Map<ValueParameterDescriptor, ValueParameterDescriptor> substitutedParametersMap = Maps.newHashMap();
198 for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
199 substitutedParametersMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
200 }
201
202 Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newLinkedHashMap(valueArguments);
203 valueArguments.clear();
204 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
205 ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(entry.getKey().getOriginal());
206 assert substitutedVersion != null : entry.getKey();
207 valueArguments.put(substitutedVersion, entry.getValue());
208 }
209
210 Map<ValueArgument, ArgumentMatchImpl> originalArgumentToParameterMap = Maps.newLinkedHashMap(argumentToParameterMap);
211 argumentToParameterMap.clear();
212 for (Map.Entry<ValueArgument, ArgumentMatchImpl> entry : originalArgumentToParameterMap.entrySet()) {
213 ArgumentMatchImpl argumentMatch = entry.getValue();
214 ValueParameterDescriptor valueParameterDescriptor = argumentMatch.getValueParameter();
215 ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(valueParameterDescriptor.getOriginal());
216 assert substitutedVersion != null : valueParameterDescriptor;
217 argumentToParameterMap.put(entry.getKey(), argumentMatch.replaceValueParameter(substitutedVersion));
218 }
219 }
220
221 @Override
222 public void setConstraintSystem(@NotNull ConstraintSystem constraintSystem) {
223 this.constraintSystem = constraintSystem;
224 }
225
226 @Nullable
227 @Override
228 public ConstraintSystem getConstraintSystem() {
229 assertNotCompleted("ConstraintSystem");
230 return constraintSystem;
231 }
232
233 @Override
234 public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
235 assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
236 valueArguments.put(valueParameter, valueArgument);
237 for (ValueArgument argument : valueArgument.getArguments()) {
238 argumentToParameterMap.put(argument, new ArgumentMatchImpl(valueParameter));
239 }
240 }
241
242 @Override
243 @NotNull
244 public Receiver getExtensionReceiver() {
245 return extensionReceiver;
246 }
247
248 @Override
249 @NotNull
250 public ReceiverValue getDispatchReceiver() {
251 return dispatchReceiver;
252 }
253
254 @Override
255 @NotNull
256 public ExplicitReceiverKind getExplicitReceiverKind() {
257 return explicitReceiverKind;
258 }
259
260 @Override
261 @NotNull
262 public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
263 return valueArguments;
264 }
265
266 @Nullable
267 @Override
268 public List<ResolvedValueArgument> getValueArgumentsByIndex() {
269 List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
270 for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
271 arguments.add(null);
272 }
273
274 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
275 ValueParameterDescriptor parameterDescriptor = entry.getKey();
276 ResolvedValueArgument value = entry.getValue();
277 ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
278 if (oldValue != null) {
279 return null;
280 }
281 }
282
283 for (int i = 0; i < arguments.size(); i++) {
284 Object o = arguments.get(i);
285 if (o == null) {
286 return null;
287 }
288 }
289
290 return arguments;
291 }
292
293 @Override
294 public void recordArgumentMatchStatus(@NotNull ValueArgument valueArgument, @NotNull ArgumentMatchStatus matchStatus) {
295 ArgumentMatchImpl argumentMatch = argumentToParameterMap.get(valueArgument);
296 argumentMatch.recordMatchStatus(matchStatus);
297 }
298
299 @NotNull
300 @Override
301 public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) {
302 ArgumentMatch argumentMatch = argumentToParameterMap.get(valueArgument);
303 if (argumentMatch == null) {
304 if (ArgumentMappingKt.isReallySuccess(this)) {
305 LOG.error("ArgumentUnmapped for " + valueArgument + " in successfully resolved call: " + call.getCallElement().getText());
306 }
307 return ArgumentUnmapped.INSTANCE$;
308 }
309 return argumentMatch;
310 }
311
312 @NotNull
313 @Override
314 public Map<TypeParameterDescriptor, KotlinType> getTypeArguments() {
315 return typeArguments;
316 }
317
318 @Override
319 public boolean isSafeCall() {
320 return CallUtilKt.isSafeCall(call);
321 }
322
323 @NotNull
324 @Override
325 public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
326 return dataFlowInfoForArguments;
327 }
328
329 @Override
330 public boolean hasInferredReturnType() {
331 if (!completed) {
332 hasInferredReturnType = constraintSystem == null ||
333 CallResolverUtilKt.hasInferredReturnType(candidateDescriptor, constraintSystem);
334 }
335 assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
336 return hasInferredReturnType;
337 }
338
339 @Override
340 public void markCallAsCompleted() {
341 if (!completed) {
342 hasInferredReturnType();
343 }
344 trace = null;
345 constraintSystem = null;
346 tracing = null;
347 completed = true;
348 }
349
350 @Override
351 public boolean isCompleted() {
352 return completed;
353 }
354
355 private void assertNotCompleted(String elementName) {
356 assert !completed: elementName + " is erased after resolution completion.";
357 }
358
359 @Override
360 @Nullable
361 public TypeSubstitutor getKnownTypeParametersSubstitutor() {
362 return knownTypeParametersSubstitutor;
363 }
364 }