001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.calls.model;
018    
019    import com.google.common.collect.Maps;
020    import com.intellij.openapi.diagnostic.Logger;
021    import com.intellij.util.Function;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.descriptors.CallableDescriptor;
025    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
026    import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
027    import org.jetbrains.kotlin.psi.Call;
028    import org.jetbrains.kotlin.psi.ValueArgument;
029    import org.jetbrains.kotlin.resolve.DelegatingBindingTrace;
030    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
031    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
032    import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
033    import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus;
034    import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
035    import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
036    import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
037    import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
038    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
039    import org.jetbrains.kotlin.types.KotlinType;
040    import org.jetbrains.kotlin.types.TypeProjection;
041    import org.jetbrains.kotlin.types.TypeSubstitutor;
042    
043    import java.util.ArrayList;
044    import java.util.List;
045    import java.util.Map;
046    
047    import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE;
048    import static org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS;
049    
050    public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableResolvedCall<D> {
051        private static final Logger LOG = Logger.getInstance(ResolvedCallImpl.class);
052    
053        public static final Function<MutableResolvedCall<?>, CallableDescriptor> MAP_TO_CANDIDATE = new Function<MutableResolvedCall<?>, CallableDescriptor>() {
054            @Override
055            public CallableDescriptor fun(MutableResolvedCall<?> resolvedCall) {
056                return resolvedCall.getCandidateDescriptor();
057            }
058        };
059    
060        public static final Function<MutableResolvedCall<?>, CallableDescriptor> MAP_TO_RESULT = new Function<MutableResolvedCall<?>, CallableDescriptor>() {
061            @Override
062            public CallableDescriptor fun(MutableResolvedCall<?> resolvedCall) {
063                return resolvedCall.getResultingDescriptor();
064            }
065        };
066    
067        @NotNull
068        public static <D extends CallableDescriptor> ResolvedCallImpl<D> create(
069                @NotNull ResolutionCandidate<D> candidate,
070                @NotNull DelegatingBindingTrace trace,
071                @NotNull TracingStrategy tracing,
072                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
073        ) {
074            return new ResolvedCallImpl<D>(candidate, trace, tracing, dataFlowInfoForArguments);
075        }
076    
077        private final Call call;
078        private final D candidateDescriptor;
079        private D resultingDescriptor; // Probably substituted
080        private final ReceiverValue dispatchReceiver; // receiver object of a method
081        private final Receiver extensionReceiver; // receiver of an extension function
082        private final ExplicitReceiverKind explicitReceiverKind;
083        private final TypeSubstitutor knownTypeParametersSubstitutor;
084    
085        private final Map<TypeParameterDescriptor, KotlinType> typeArguments = Maps.newLinkedHashMap();
086        private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
087        private final MutableDataFlowInfoForArguments dataFlowInfoForArguments;
088        private final Map<ValueArgument, ArgumentMatchImpl> argumentToParameterMap = Maps.newHashMap();
089    
090        private DelegatingBindingTrace trace;
091        private TracingStrategy tracing;
092        private ResolutionStatus status = UNKNOWN_STATUS;
093        private ConstraintSystem constraintSystem = null;
094        private Boolean hasInferredReturnType = null;
095        private boolean completed = false;
096    
097        private ResolvedCallImpl(
098                @NotNull ResolutionCandidate<D> candidate,
099                @NotNull DelegatingBindingTrace trace,
100                @NotNull TracingStrategy tracing,
101                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
102        ) {
103            this.call = candidate.getCall();
104            this.candidateDescriptor = candidate.getDescriptor();
105            this.dispatchReceiver = candidate.getDispatchReceiver();
106            this.extensionReceiver = candidate.getReceiverArgument();
107            this.explicitReceiverKind = candidate.getExplicitReceiverKind();
108            this.knownTypeParametersSubstitutor = candidate.getKnownTypeParametersResultingSubstitutor();
109            this.trace = trace;
110            this.tracing = tracing;
111            this.dataFlowInfoForArguments = dataFlowInfoForArguments;
112        }
113    
114        public ResolvedCallImpl(
115                @NotNull Call call,
116                @NotNull D candidateDescriptor,
117                @NotNull ReceiverValue dispatchReceiver,
118                @NotNull ReceiverValue extensionReceiver,
119                @NotNull ExplicitReceiverKind explicitReceiverKind,
120                @Nullable TypeSubstitutor knownTypeParametersSubstitutor,
121                @NotNull DelegatingBindingTrace trace,
122                @NotNull TracingStrategy tracing,
123                @NotNull MutableDataFlowInfoForArguments dataFlowInfoForArguments
124        ) {
125            this.call = call;
126            this.candidateDescriptor = candidateDescriptor;
127            this.dispatchReceiver = dispatchReceiver;
128            this.extensionReceiver = extensionReceiver;
129            this.explicitReceiverKind = explicitReceiverKind;
130            this.knownTypeParametersSubstitutor = knownTypeParametersSubstitutor;
131            this.trace = trace;
132            this.tracing = tracing;
133            this.dataFlowInfoForArguments = dataFlowInfoForArguments;
134        }
135    
136        @Override
137        @NotNull
138        public ResolutionStatus getStatus() {
139            return status;
140        }
141    
142        @Override
143        public void addStatus(@NotNull ResolutionStatus status) {
144            this.status = this.status.combine(status);
145        }
146    
147        @Override
148        public void setStatusToSuccess() {
149            assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
150            status = ResolutionStatus.SUCCESS;
151        }
152    
153        @Override
154        @NotNull
155        public DelegatingBindingTrace getTrace() {
156            assertNotCompleted("Trace");
157            return trace;
158        }
159    
160        @Override
161        @NotNull
162        public TracingStrategy getTracingStrategy() {
163            assertNotCompleted("TracingStrategy");
164            return tracing;
165        }
166    
167        @NotNull
168        @Override
169        public Call getCall() {
170            return call;
171        }
172    
173        @Override
174        @NotNull
175        public D getCandidateDescriptor() {
176            return candidateDescriptor;
177        }
178    
179        @Override
180        @NotNull
181        public D getResultingDescriptor() {
182            return resultingDescriptor == null ? candidateDescriptor : resultingDescriptor;
183        }
184    
185        @Override
186        public void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor) {
187            resultingDescriptor = (D) candidateDescriptor.substitute(substitutor);
188            assert resultingDescriptor != null : candidateDescriptor;
189    
190            for (TypeParameterDescriptor typeParameter : candidateDescriptor.getTypeParameters()) {
191                TypeProjection typeArgumentProjection = substitutor.getSubstitution().get(typeParameter.getDefaultType());
192                if (typeArgumentProjection != null) {
193                    typeArguments.put(typeParameter, typeArgumentProjection.getType());
194                }
195            }
196    
197            Map<ValueParameterDescriptor, ValueParameterDescriptor> substitutedParametersMap = Maps.newHashMap();
198            for (ValueParameterDescriptor valueParameterDescriptor : resultingDescriptor.getValueParameters()) {
199                substitutedParametersMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
200            }
201    
202            Map<ValueParameterDescriptor, ResolvedValueArgument> originalValueArguments = Maps.newLinkedHashMap(valueArguments);
203            valueArguments.clear();
204            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : originalValueArguments.entrySet()) {
205                ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(entry.getKey().getOriginal());
206                assert substitutedVersion != null : entry.getKey();
207                valueArguments.put(substitutedVersion, entry.getValue());
208            }
209    
210            Map<ValueArgument, ArgumentMatchImpl> originalArgumentToParameterMap = Maps.newLinkedHashMap(argumentToParameterMap);
211            argumentToParameterMap.clear();
212            for (Map.Entry<ValueArgument, ArgumentMatchImpl> entry : originalArgumentToParameterMap.entrySet()) {
213                ArgumentMatchImpl argumentMatch = entry.getValue();
214                ValueParameterDescriptor valueParameterDescriptor = argumentMatch.getValueParameter();
215                ValueParameterDescriptor substitutedVersion = substitutedParametersMap.get(valueParameterDescriptor.getOriginal());
216                assert substitutedVersion != null : valueParameterDescriptor;
217                argumentToParameterMap.put(entry.getKey(), argumentMatch.replaceValueParameter(substitutedVersion));
218            }
219        }
220    
221        @Override
222        public void setConstraintSystem(@NotNull ConstraintSystem constraintSystem) {
223            this.constraintSystem = constraintSystem;
224        }
225    
226        @Nullable
227        @Override
228        public ConstraintSystem getConstraintSystem() {
229            assertNotCompleted("ConstraintSystem");
230            return constraintSystem;
231        }
232    
233        @Override
234        public void recordValueArgument(@NotNull ValueParameterDescriptor valueParameter, @NotNull ResolvedValueArgument valueArgument) {
235            assert !valueArguments.containsKey(valueParameter) : valueParameter + " -> " + valueArgument;
236            valueArguments.put(valueParameter, valueArgument);
237            for (ValueArgument argument : valueArgument.getArguments()) {
238                argumentToParameterMap.put(argument, new ArgumentMatchImpl(valueParameter));
239            }
240        }
241    
242        @Override
243        @NotNull
244        public Receiver getExtensionReceiver() {
245            return extensionReceiver;
246        }
247    
248        @Override
249        @NotNull
250        public ReceiverValue getDispatchReceiver() {
251            return dispatchReceiver;
252        }
253    
254        @Override
255        @NotNull
256        public ExplicitReceiverKind getExplicitReceiverKind() {
257            return explicitReceiverKind;
258        }
259    
260        @Override
261        @NotNull
262        public Map<ValueParameterDescriptor, ResolvedValueArgument> getValueArguments() {
263            return valueArguments;
264        }
265    
266        @Nullable
267        @Override
268        public List<ResolvedValueArgument> getValueArgumentsByIndex() {
269            List<ResolvedValueArgument> arguments = new ArrayList<ResolvedValueArgument>(candidateDescriptor.getValueParameters().size());
270            for (int i = 0; i < candidateDescriptor.getValueParameters().size(); ++i) {
271                arguments.add(null);
272            }
273            
274            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : valueArguments.entrySet()) {
275                ValueParameterDescriptor parameterDescriptor = entry.getKey();
276                ResolvedValueArgument value = entry.getValue();
277                ResolvedValueArgument oldValue = arguments.set(parameterDescriptor.getIndex(), value);
278                if (oldValue != null) {
279                    return null;
280                }
281            }
282    
283            for (int i = 0; i < arguments.size(); i++) {
284                Object o = arguments.get(i);
285                if (o == null) {
286                    return null;
287                }
288            }
289            
290            return arguments;
291        }
292    
293        @Override
294        public void recordArgumentMatchStatus(@NotNull ValueArgument valueArgument, @NotNull ArgumentMatchStatus matchStatus) {
295            ArgumentMatchImpl argumentMatch = argumentToParameterMap.get(valueArgument);
296            argumentMatch.recordMatchStatus(matchStatus);
297        }
298    
299        @NotNull
300        @Override
301        public ArgumentMapping getArgumentMapping(@NotNull ValueArgument valueArgument) {
302            ArgumentMatch argumentMatch = argumentToParameterMap.get(valueArgument);
303            if (argumentMatch == null) {
304                if (ArgumentMappingKt.isReallySuccess(this)) {
305                    LOG.error("ArgumentUnmapped for " + valueArgument + " in successfully resolved call: " + call.getCallElement().getText());
306                }
307                return ArgumentUnmapped.INSTANCE$;
308            }
309            return argumentMatch;
310        }
311    
312        @NotNull
313        @Override
314        public Map<TypeParameterDescriptor, KotlinType> getTypeArguments() {
315            return typeArguments;
316        }
317    
318        @Override
319        public boolean isSafeCall() {
320            return CallUtilKt.isSafeCall(call);
321        }
322    
323        @NotNull
324        @Override
325        public MutableDataFlowInfoForArguments getDataFlowInfoForArguments() {
326            return dataFlowInfoForArguments;
327        }
328    
329        @Override
330        public boolean hasInferredReturnType() {
331            if (!completed) {
332                hasInferredReturnType = constraintSystem == null ||
333                                        CallResolverUtilKt.hasInferredReturnType(candidateDescriptor, constraintSystem);
334            }
335            assert hasInferredReturnType != null : "The property 'hasInferredReturnType' was not set when the call was completed.";
336            return hasInferredReturnType;
337        }
338    
339        @Override
340        public void markCallAsCompleted() {
341            if (!completed) {
342                hasInferredReturnType();
343            }
344            trace = null;
345            constraintSystem = null;
346            tracing = null;
347            completed = true;
348        }
349    
350        @Override
351        public boolean isCompleted() {
352            return completed;
353        }
354    
355        private void assertNotCompleted(String elementName) {
356            assert !completed: elementName + " is erased after resolution completion.";
357        }
358    
359        @Override
360        @Nullable
361        public TypeSubstitutor getKnownTypeParametersSubstitutor() {
362            return knownTypeParametersSubstitutor;
363        }
364    }