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