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