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