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