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    }