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.tasks;
018    
019    import com.google.common.collect.Sets;
020    import com.intellij.lang.ASTNode;
021    import com.intellij.psi.PsiElement;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.psi.*;
025    import org.jetbrains.jet.lang.resolve.BindingTrace;
026    import org.jetbrains.jet.lang.resolve.calls.inference.*;
027    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
028    import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
029    import org.jetbrains.jet.lang.resolve.name.Name;
030    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
031    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
032    import org.jetbrains.jet.lang.types.ErrorUtils;
033    import org.jetbrains.jet.lang.types.JetType;
034    import org.jetbrains.jet.lang.types.Variance;
035    import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
036    import org.jetbrains.jet.lexer.JetToken;
037    import org.jetbrains.jet.lexer.JetTokens;
038    
039    import java.util.Collection;
040    import java.util.List;
041    
042    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
043    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
044    import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
045    
046    public class TracingStrategyImpl implements TracingStrategy {
047        private final JetReferenceExpression reference;
048        private final Call call;
049    
050        private TracingStrategyImpl(@NotNull JetReferenceExpression reference, @NotNull Call call) {
051            this.reference = reference;
052            this.call = call;
053        }
054    
055        @NotNull
056        public static TracingStrategy create(@NotNull JetReferenceExpression reference, @NotNull Call call) {
057            return new TracingStrategyImpl(reference, call);
058        }
059    
060        @Override
061        public <D extends CallableDescriptor> void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall) {
062            CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
063            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
064                descriptor = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor();
065            }
066            DeclarationDescriptor storedReference = trace.get(REFERENCE_TARGET, reference);
067            if (storedReference == null || !ErrorUtils.isError(descriptor)) {
068                trace.record(REFERENCE_TARGET, reference, descriptor);
069            }
070        }
071    
072        @Override
073        public <D extends CallableDescriptor> void bindResolvedCall(@NotNull BindingTrace trace, @NotNull ResolvedCallWithTrace<D> resolvedCall) {
074            trace.record(RESOLVED_CALL, call.getCalleeExpression(), resolvedCall);
075            trace.record(CALL, call.getCalleeExpression(), call);
076        }
077    
078        @Override
079        public <D extends CallableDescriptor> void recordAmbiguity(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates) {
080            Collection<D> descriptors = Sets.newHashSet();
081            for (ResolvedCallWithTrace<D> candidate : candidates) {
082                descriptors.add(candidate.getCandidateDescriptor());
083            }
084            trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, descriptors);
085        }
086    
087        @Override
088        public void unresolvedReference(@NotNull BindingTrace trace) {
089            trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
090        }
091    
092        @Override
093        public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> candidates) {
094            trace.report(UNRESOLVED_REFERENCE_WRONG_RECEIVER.on(reference, candidates));
095        }
096    
097        @Override
098        public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) {
099            JetElement reportOn;
100            JetValueArgumentList valueArgumentList = call.getValueArgumentList();
101            if (valueArgumentList != null) {
102                reportOn = valueArgumentList;
103            }
104            else {
105                reportOn = reference;
106            }
107            trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter));
108        }
109    
110        @Override
111        public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {
112            trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType()));
113        }
114    
115        @Override
116        public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument) {
117            if (receiverArgument instanceof ExpressionReceiver) {
118                ExpressionReceiver expressionReceiver = (ExpressionReceiver)receiverArgument;
119                trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType()));
120            }
121            else {
122                trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType()));
123            }
124        }
125    
126        @Override
127        public void noReceiverAllowed(@NotNull BindingTrace trace) {
128            trace.report(NO_RECEIVER_ADMITTED.on(reference));
129        }
130    
131        @Override
132        public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
133            JetTypeArgumentList typeArgumentList = call.getTypeArgumentList();
134            if (typeArgumentList != null) {
135                trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentList, expectedTypeArgumentCount));
136            }
137            else {
138                trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(reference, expectedTypeArgumentCount));
139            }
140        }
141    
142        @Override
143        public <D extends CallableDescriptor> void ambiguity(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors) {
144            trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(reference, descriptors));
145        }
146    
147        @Override
148        public <D extends CallableDescriptor> void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection<ResolvedCallWithTrace<D>> descriptors) {
149            trace.report(NONE_APPLICABLE.on(reference, descriptors));
150        }
151    
152        @Override
153        public <D extends CallableDescriptor> void cannotCompleteResolve(
154                @NotNull BindingTrace trace,
155                @NotNull Collection<ResolvedCallWithTrace<D>> descriptors
156        ) {
157            trace.report(CANNOT_COMPLETE_RESOLVE.on(reference, descriptors));
158        }
159    
160        @Override
161        public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
162            trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(call.getCallElement()));
163        }
164    
165        @Override
166        public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {
167            ASTNode callOperationNode = call.getCallOperationNode();
168            if (callOperationNode != null && !isCallForImplicitInvoke) {
169                trace.report(UNSAFE_CALL.on(callOperationNode.getPsi(), type));
170            }
171            else {
172                PsiElement callElement = call.getCallElement();
173                if (callElement instanceof JetBinaryExpression) {
174                    JetBinaryExpression binaryExpression = (JetBinaryExpression)callElement;
175                    JetSimpleNameExpression operationReference = binaryExpression.getOperationReference();
176    
177                    Name operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ?
178                            Name.identifier(operationReference.getText()) :
179                            OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType());
180    
181                    JetExpression left = binaryExpression.getLeft();
182                    JetExpression right = binaryExpression.getRight();
183                    if (left != null && right != null) {
184                        trace.report(UNSAFE_INFIX_CALL.on(reference, left.getText(), operationString.asString(), right.getText()));
185                    }
186                }
187                else {
188                    trace.report(UNSAFE_CALL.on(reference, type));
189                }
190            }
191        }
192    
193        @Override
194        public void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type) {
195            ASTNode callOperationNode = call.getCallOperationNode();
196            assert callOperationNode != null;
197            trace.report(UNNECESSARY_SAFE_CALL.on(callOperationNode.getPsi(), type));
198        }
199    
200        @Override
201        public void danglingFunctionLiteralArgumentSuspected(@NotNull BindingTrace trace, @NotNull List<JetExpression> functionLiteralArguments) {
202            for (JetExpression functionLiteralArgument : functionLiteralArguments) {
203                trace.report(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED.on(functionLiteralArgument));
204            }
205        }
206    
207        @Override
208        public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {
209            trace.report(INVISIBLE_MEMBER.on(call.getCallElement(), descriptor, descriptor.getVisibility(), descriptor.getContainingDeclaration()));
210        }
211    
212        @Override
213        public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData data) {
214            ConstraintSystem constraintSystem = data.constraintSystem;
215            ConstraintSystemStatus status = constraintSystem.getStatus();
216            assert !status.isSuccessful() : "Report error only for not successful constraint system";
217    
218            if (status.hasErrorInConstrainingTypes()) {
219                // Do not report type inference errors if there is one in the arguments
220                // (it's useful, when the arguments, e.g. lambdas or calls are incomplete)
221                return;
222            }
223            if (status.hasOnlyErrorsFromPosition(ConstraintPosition.EXPECTED_TYPE_POSITION)) {
224                JetType declaredReturnType = data.descriptor.getReturnType();
225                if (declaredReturnType == null) return;
226    
227                ConstraintSystem systemWithoutExpectedTypeConstraint =
228                        ((ConstraintSystemImpl) constraintSystem).filterConstraintsOut(ConstraintPosition.EXPECTED_TYPE_POSITION);
229                JetType substitutedReturnType = systemWithoutExpectedTypeConstraint.getResultingSubstitutor().substitute(declaredReturnType, Variance.INVARIANT);
230                assert substitutedReturnType != null; //todo
231    
232                assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
233                trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(reference, data.expectedType, substitutedReturnType));
234            }
235            else if (status.hasViolatedUpperBound()) {
236                trace.report(TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, data));
237            }
238            else if (status.hasTypeConstructorMismatch()) {
239                trace.report(TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH.on(reference, data));
240            }
241            else if (status.hasConflictingConstraints()) {
242                trace.report(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data));
243            }
244            else {
245                assert status.hasUnknownParameters();
246                trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
247            }
248        }
249    }