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                if (arguments.set(entry.getKey().getIndex(), entry.getValue()) != null) {
242                    throw new IllegalStateException();
243                }
244            }
245    
246            for (Object o : arguments) {
247                if (o == null) {
248                    throw new IllegalStateException();
249                }
250            }
251            
252            return arguments;
253        }
254    
255        public void argumentHasNoType() {
256            this.someArgumentHasNoType = true;
257        }
258    
259        @Override
260        public boolean isDirty() {
261            return someArgumentHasNoType;
262        }
263    
264        @NotNull
265        @Override
266        public Map<TypeParameterDescriptor, JetType> getTypeArguments() {
267            return typeArguments;
268        }
269    
270        @Override
271        public boolean isSafeCall() {
272            return isSafeCall;
273        }
274    
275        public void setInitialDataFlowInfo(@NotNull DataFlowInfo info) {
276            dataFlowInfoForArguments.setInitialDataFlowInfo(info);
277        }
278    
279        @NotNull
280        @Override
281        public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
282            return dataFlowInfoForArguments;
283        }
284    
285        @NotNull
286        @Override
287        public ResolvedCallImpl<D> getCallToCompleteTypeArgumentInference() {
288            return this;
289        }
290    
291        public boolean hasInferredReturnType() {
292            if (!completed) {
293                hasInferredReturnType = constraintSystem == null || CallResolverUtil.hasInferredReturnType(candidateDescriptor, constraintSystem);
294            }
295            assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
296            return hasInferredReturnType;
297        }
298    
299        @Override
300        public void markCallAsCompleted() {
301            if (!completed) {
302                hasInferredReturnType();
303            }
304            trace = null;
305            constraintSystem = null;
306            tracing = null;
307            completed = true;
308        }
309    
310        @Override
311        public boolean isCompleted() {
312            return completed;
313        }
314    
315        private void assertNotCompleted(String elementName) {
316            assert !completed: elementName + " is erased after resolution completion.";
317        }
318    }