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.google.common.collect.Sets;
021 import com.intellij.util.Function;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
025 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
026 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
027 import org.jetbrains.jet.lang.psi.Call;
028 import org.jetbrains.jet.lang.psi.ValueArgument;
029 import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
030 import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
031 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
032 import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
033 import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
034 import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
035 import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
036 import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
037 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
038 import org.jetbrains.jet.lang.types.JetType;
039 import org.jetbrains.jet.lang.types.TypeProjection;
040 import org.jetbrains.jet.lang.types.TypeSubstitutor;
041
042 import java.util.*;
043
044 import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE;
045 import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS;
046
047 public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableResolvedCall<D> {
048
049 public static final Function<MutableResolvedCall<?>, CallableDescriptor> MAP_TO_CANDIDATE = new Function<MutableResolvedCall<?>, CallableDescriptor>() {
050 @Override
051 public CallableDescriptor fun(MutableResolvedCall<?> resolvedCall) {
052 return resolvedCall.getCandidateDescriptor();
053 }
054 };
055
056 public static final Function<MutableResolvedCall<?>, CallableDescriptor> MAP_TO_RESULT = new Function<MutableResolvedCall<?>, CallableDescriptor>() {
057 @Override
058 public CallableDescriptor fun(MutableResolvedCall<?> resolvedCall) {
059 return resolvedCall.getResultingDescriptor();
060 }
061 };
062
063 @NotNull
064 public static <D extends CallableDescriptor> ResolvedCallImpl<D> create(
065 @NotNull ResolutionCandidate<D> candidate,
066 @NotNull DelegatingBindingTrace trace,
067 @NotNull TracingStrategy tracing,
068 @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
069 ) {
070 return new ResolvedCallImpl<D>(candidate, trace, tracing, dataFlowInfoForArguments);
071 }
072
073 private final Call call;
074 private final D candidateDescriptor;
075 private D resultingDescriptor; // Probably substituted
076 private final ReceiverValue thisObject; // receiver object of a method
077 private final ReceiverValue receiverArgument; // receiver of an extension function
078 private final ExplicitReceiverKind explicitReceiverKind;
079 private final boolean isSafeCall;
080
081 private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
082 private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
083 private final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
084 private final Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
085 private final Map<ValueArgument, ArgumentMatch> argumentToParameterMap = Maps.newHashMap();
086
087 private boolean someArgumentHasNoType = false;
088 private DelegatingBindingTrace trace;
089 private TracingStrategy tracing;
090 private ResolutionStatus status = UNKNOWN_STATUS;
091 private boolean hasUnknownTypeParameters = false;
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.thisObject = candidate.getThisObject();
105 this.receiverArgument = candidate.getReceiverArgument();
106 this.explicitReceiverKind = candidate.getExplicitReceiverKind();
107 this.isSafeCall = candidate.isSafeCall();
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 public boolean hasIncompleteTypeParameters() {
132 return hasUnknownTypeParameters;
133 }
134
135 @Override
136 public void setHasIncompleteTypeParameters(boolean hasIncompleteTypeParameters) {
137 this.hasUnknownTypeParameters = hasIncompleteTypeParameters;
138 }
139
140 @Override
141 @NotNull
142 public DelegatingBindingTrace getTrace() {
143 assertNotCompleted("Trace");
144 return trace;
145 }
146
147 @NotNull
148 public TracingStrategy getTracing() {
149 assertNotCompleted("TracingStrategy");
150 return tracing;
151 }
152
153 @NotNull
154 @Override
155 public Call getCall() {
156 return call;
157 }
158
159 @Override
160 @NotNull
161 public D getCandidateDescriptor() {
162 return candidateDescriptor;
163 }
164
165 @Override
166 @NotNull
167 public D getResultingDescriptor() {
168 return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
169 }
170
171 @Override
172 public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
173 resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
174 assert resultingDescriptor != null : candidateDescriptor;
175
176 for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
177 TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getTypeConstructor());
178 if (typeArgumentProjection != null) {
179 typeArguments.put(typeParameter, typeArgumentProjection.getType());
180 }
181 }
182
183 Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
184 for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
185 parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
186 }
187
188 Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newLinkedHashMap(valueArguments);
189 valueArguments.clear();
190 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
191 ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal());
192 assert substitutedVersion != null : entry.getKey();
193 valueArguments.put(substitutedVersion, entry.getValue());
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 }
214
215 @Override
216 public void addUnmappedArguments(@NotNull Collection<? extends ValueArgument> unmappedArguments) {
217 this.unmappedArguments.addAll(unmappedArguments);
218
219 }
220
221 @Override
222 @NotNull
223 public Set<ValueArgument> getUnmappedArguments() {
224 return unmappedArguments;
225 }
226
227 @Override
228 @NotNull
229 public ReceiverValue getReceiverArgument() {
230 return receiverArgument;
231 }
232
233 @Override
234 @NotNull
235 public ReceiverValue getThisObject() {
236 return thisObject;
237 }
238
239 @Override
240 @NotNull
241 public ExplicitReceiverKind getExplicitReceiverKind() {
242 return explicitReceiverKind;
243 }
244
245 @Override
246 @NotNull
247 public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
248 return valueArguments;
249 }
250
251 @Nullable
252 @Override
253 public List<ResolvedValueArgument> getValueArgumentsByIndex() {
254 List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
255 for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
256 arguments.add(null);
257 }
258
259 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
260 ValueParameterDescriptor parameterDescriptor = entry.getKey();
261 ResolvedValueArgument value = entry.getValue();
262 ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
263 if (oldValue != null) {
264 return null;
265 }
266 }
267
268 for (int i = 0; i < arguments.size(); i++) {
269 Object o = arguments.get(i);
270 if (o == null) {
271 return null;
272 }
273 }
274
275 return arguments;
276 }
277
278 @Override
279 public void recordArgumentMatch(
280 @NotNull ValueArgument valueArgument, @NotNull ValueParameterDescriptor parameter, boolean hasTypeMismatch
281 ) {
282 argumentToParameterMap.put(valueArgument, new ArgumentMatch(parameter, hasTypeMismatch));
283 }
284
285 @NotNull
286 @Override
287 public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) {
288 ArgumentMatch argumentMatch = argumentToParameterMap.get(valueArgument);
289 if (argumentMatch == null) {
290 return ArgumentUnmapped.instance$;
291 }
292 return argumentMatch;
293 }
294
295 @Override
296 public void argumentHasNoType() {
297 this.someArgumentHasNoType = true;
298 }
299
300 @Override
301 public boolean isDirty() {
302 return someArgumentHasNoType;
303 }
304
305 @NotNull
306 @Override
307 public Map<TypeParameterDescriptor, JetType> getTypeArguments() {
308 return typeArguments;
309 }
310
311 @Override
312 public boolean isSafeCall() {
313 return isSafeCall;
314 }
315
316 @Override
317 public void setInitialDataFlowInfo(@NotNull DataFlowInfo info) {
318 dataFlowInfoForArguments.setInitialDataFlowInfo(info);
319 }
320
321 @NotNull
322 @Override
323 public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
324 return dataFlowInfoForArguments;
325 }
326
327 @Override
328 public boolean hasInferredReturnType() {
329 if (!completed) {
330 hasInferredReturnType = constraintSystem == null || CallResolverUtil.hasInferredReturnType(candidateDescriptor, constraintSystem);
331 }
332 assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
333 return hasInferredReturnType;
334 }
335
336 @Override
337 public void markCallAsCompleted() {
338 if (!completed) {
339 hasInferredReturnType();
340 }
341 trace = null;
342 constraintSystem = null;
343 tracing = null;
344 completed = true;
345 }
346
347 @Override
348 public boolean isCompleted() {
349 return completed;
350 }
351
352 private void assertNotCompleted(String elementName) {
353 assert !completed: elementName + " is erased after resolution completion.";
354 }
355 }