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