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