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