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