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 ResolvedCallWithTrace<D> {
048
049 public static final Function<ResolvedCallWithTrace<?>, CallableDescriptor> MAP_TO_CANDIDATE = new Function<ResolvedCallWithTrace<?>, CallableDescriptor>() {
050 @Override
051 public CallableDescriptor fun(ResolvedCallWithTrace<?> resolvedCall) {
052 return resolvedCall.getCandidateDescriptor();
053 }
054 };
055
056 public static final Function<ResolvedCallWithTrace<?>, CallableDescriptor> MAP_TO_RESULT = new Function<ResolvedCallWithTrace<?>, CallableDescriptor>() {
057 @Override
058 public CallableDescriptor fun(ResolvedCallWithTrace<?> 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
086 private boolean someArgumentHasNoType = false;
087 private DelegatingBindingTrace trace;
088 private TracingStrategy tracing;
089 private ResolutionStatus status = UNKNOWN_STATUS;
090 private boolean hasUnknownTypeParameters = false;
091 private ConstraintSystem constraintSystem = null;
092 private Boolean hasInferredReturnType = null;
093 private boolean completed = false;
094
095 private ResolvedCallImpl(
096 @NotNull ResolutionCandidate<D> candidate,
097 @NotNull DelegatingBindingTrace trace,
098 @NotNull TracingStrategy tracing,
099 @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
100 ) {
101 this.call = candidate.getCall();
102 this.candidateDescriptor = candidate.getDescriptor();
103 this.thisObject = candidate.getThisObject();
104 this.receiverArgument = candidate.getReceiverArgument();
105 this.explicitReceiverKind = candidate.getExplicitReceiverKind();
106 this.isSafeCall = candidate.isSafeCall();
107 this.trace = trace;
108 this.tracing = tracing;
109 this.dataFlowInfoForArguments = dataFlowInfoForArguments;
110 }
111
112 @Override
113 @NotNull
114 public ResolutionStatus getStatus() {
115 return status;
116 }
117
118 public void addStatus(@NotNull ResolutionStatus status) {
119 this.status = this.status.combine(status);
120 }
121
122 public void setStatusToSuccess() {
123 assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
124 status = ResolutionStatus.SUCCESS;
125 }
126
127 @Override
128 public boolean hasIncompleteTypeParameters() {
129 return hasUnknownTypeParameters;
130 }
131
132 public void setHasUnknownTypeParameters(boolean hasUnknownTypeParameters) {
133 this.hasUnknownTypeParameters = hasUnknownTypeParameters;
134 }
135
136 @Override
137 @NotNull
138 public DelegatingBindingTrace getTrace() {
139 assertNotCompleted("Trace");
140 return trace;
141 }
142
143 @NotNull
144 public TracingStrategy getTracing() {
145 assertNotCompleted("TracingStrategy");
146 return tracing;
147 }
148
149 @NotNull
150 @Override
151 public Call getCall() {
152 return call;
153 }
154
155 @Override
156 @NotNull
157 public D getCandidateDescriptor() {
158 return candidateDescriptor;
159 }
160
161 @Override
162 @NotNull
163 public D getResultingDescriptor() {
164 return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
165 }
166
167 public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
168 resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
169 assert resultingDescriptor != null : candidateDescriptor;
170
171 for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
172 TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getTypeConstructor());
173 if (typeArgumentProjection != null) {
174 typeArguments.put(typeParameter, typeArgumentProjection.getType());
175 }
176 }
177
178 Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
179 for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
180 parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
181 }
182
183 Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newLinkedHashMap(valueArguments);
184 valueArguments.clear();
185 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
186 ValueParameterDescriptor substitutedVersion = parameterMap.get(entry.getKey().getOriginal());
187 assert substitutedVersion != null : entry.getKey();
188 valueArguments.put(substitutedVersion, entry.getValue());
189 }
190 }
191
192 public void setConstraintSystem(@NotNull ConstraintSystem constraintSystem) {
193 this.constraintSystem = constraintSystem;
194 }
195
196 @Nullable
197 public ConstraintSystem getConstraintSystem() {
198 assertNotCompleted("ConstraintSystem");
199 return constraintSystem;
200 }
201
202 public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
203 assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
204 valueArguments.put(valueParameter, valueArgument);
205 }
206
207 public void setUnmappedArguments(@NotNull Collection<? extends ValueArgument> unmappedArguments) {
208 this.unmappedArguments.addAll(unmappedArguments);
209
210 }
211
212 @NotNull
213 public Set<ValueArgument> getUnmappedArguments() {
214 return unmappedArguments;
215 }
216
217 @Override
218 @NotNull
219 public ReceiverValue getReceiverArgument() {
220 return receiverArgument;
221 }
222
223 @Override
224 @NotNull
225 public ReceiverValue getThisObject() {
226 return thisObject;
227 }
228
229 @Override
230 @NotNull
231 public ExplicitReceiverKind getExplicitReceiverKind() {
232 return explicitReceiverKind;
233 }
234
235 @Override
236 @NotNull
237 public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
238 return valueArguments;
239 }
240
241 @Nullable
242 @Override
243 public List<ResolvedValueArgument> getValueArgumentsByIndex() {
244 List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
245 for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
246 arguments.add(null);
247 }
248
249 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
250 ValueParameterDescriptor parameterDescriptor = entry.getKey();
251 ResolvedValueArgument value = entry.getValue();
252 ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
253 if (oldValue != null) {
254 return null;
255 }
256 }
257
258 for (int i = 0; i < arguments.size(); i++) {
259 Object o = arguments.get(i);
260 if (o == null) {
261 return null;
262 }
263 }
264
265 return arguments;
266 }
267
268 public void argumentHasNoType() {
269 this.someArgumentHasNoType = true;
270 }
271
272 @Override
273 public boolean isDirty() {
274 return someArgumentHasNoType;
275 }
276
277 @NotNull
278 @Override
279 public Map<TypeParameterDescriptor, JetType> getTypeArguments() {
280 return typeArguments;
281 }
282
283 @Override
284 public boolean isSafeCall() {
285 return isSafeCall;
286 }
287
288 public void setInitialDataFlowInfo(@NotNull DataFlowInfo info) {
289 dataFlowInfoForArguments.setInitialDataFlowInfo(info);
290 }
291
292 @NotNull
293 @Override
294 public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
295 return dataFlowInfoForArguments;
296 }
297
298 @NotNull
299 @Override
300 public ResolvedCallImpl<D> getCallToCompleteTypeArgumentInference() {
301 return this;
302 }
303
304 public boolean hasInferredReturnType() {
305 if (!completed) {
306 hasInferredReturnType = constraintSystem == null || CallResolverUtil.hasInferredReturnType(candidateDescriptor, constraintSystem);
307 }
308 assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
309 return hasInferredReturnType;
310 }
311
312 @Override
313 public void markCallAsCompleted() {
314 if (!completed) {
315 hasInferredReturnType();
316 }
317 trace = null;
318 constraintSystem = null;
319 tracing = null;
320 completed = true;
321 }
322
323 @Override
324 public boolean isCompleted() {
325 return completed;
326 }
327
328 private void assertNotCompleted(String elementName) {
329 assert !completed: elementName + " is erased after resolution completion.";
330 }
331 }