org.jetbrains.kotlin.resolve.calls.tasks.AbstractTracingStrategy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.calls.tasks;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.util.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus;
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.Variance;
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import java.util.Collection;
import java.util.HashSet;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqNameFromTopLevelClass;
import static org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemUtilsKt.filterConstraintsOut;
import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION;
import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
public abstract class AbstractTracingStrategy implements TracingStrategy {
protected final KtExpression reference;
protected final Call call;
protected AbstractTracingStrategy(@NotNull KtExpression reference, @NotNull Call call) {
this.reference = reference;
this.call = call;
}
@Override
public void recordAmbiguity(@NotNull BindingTrace trace, @NotNull Collection extends ResolvedCall> candidates) {
Collection descriptors = new HashSet<>();
for (ResolvedCall candidate : candidates) {
descriptors.add(candidate.getCandidateDescriptor());
}
trace.record(AMBIGUOUS_REFERENCE_TARGET, reference, descriptors);
}
@Override
public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) {
KtElement reportOn = CallUtilKt.getValueArgumentListOrElement(call);
trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter));
}
@Override
public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {
trace.report(MISSING_RECEIVER.on(reference, expectedReceiver.getType()));
}
@Override
public void wrongReceiverType(
@NotNull BindingTrace trace,
@NotNull ReceiverParameterDescriptor receiverParameter,
@NotNull ReceiverValue receiverArgument,
@NotNull ResolutionContext> c
) {
KtExpression reportOn = receiverArgument instanceof ExpressionReceiver
? ((ExpressionReceiver) receiverArgument).getExpression()
: reference;
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(
c, reportOn, receiverParameter.getType(), receiverArgument.getType())) {
trace.report(TYPE_MISMATCH.on(reportOn, receiverParameter.getType(), receiverArgument.getType()));
}
}
@Override
public void noReceiverAllowed(@NotNull BindingTrace trace) {
trace.report(NO_RECEIVER_ALLOWED.on(reference));
}
@Override
public void wrongNumberOfTypeArguments(
@NotNull BindingTrace trace, int expectedTypeArgumentCount, @NotNull CallableDescriptor descriptor
) {
KtTypeArgumentList typeArgumentList = call.getTypeArgumentList();
trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(
typeArgumentList != null ? typeArgumentList : reference, expectedTypeArgumentCount, descriptor
));
}
@Override
public void ambiguity(@NotNull BindingTrace trace, @NotNull Collection extends ResolvedCall> resolvedCalls) {
trace.report(OVERLOAD_RESOLUTION_AMBIGUITY.on(reference, resolvedCalls));
}
@Override
public void noneApplicable(@NotNull BindingTrace trace, @NotNull Collection extends ResolvedCall> descriptors) {
trace.report(NONE_APPLICABLE.on(reference, descriptors));
}
@Override
public void cannotCompleteResolve(
@NotNull BindingTrace trace,
@NotNull Collection extends ResolvedCall> descriptors
) {
trace.report(CANNOT_COMPLETE_RESOLVE.on(reference, descriptors));
}
@Override
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(call.getCallElement()));
}
@Override
public void recursiveType(@NotNull BindingTrace trace, @NotNull LanguageVersionSettings languageVersionSettings, boolean insideAugmentedAssignment) {
KtExpression expression = call.getCalleeExpression();
if (expression == null) return;
if (insideAugmentedAssignment) {
trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM_IN_AUGMENTED_ASSIGNMENT.on(languageVersionSettings, expression));
} else {
trace.report(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM.on(languageVersionSettings, expression));
}
}
@Override
public void abstractSuperCall(@NotNull BindingTrace trace) {
trace.report(ABSTRACT_SUPER_CALL.on(reference));
}
@Override
public void abstractSuperCallWarning(@NotNull BindingTrace trace) {
trace.report(ABSTRACT_SUPER_CALL_WARNING.on(reference));
}
@Override
public void nestedClassAccessViaInstanceReference(
@NotNull BindingTrace trace,
@NotNull ClassDescriptor classDescriptor,
@NotNull ExplicitReceiverKind explicitReceiverKind
) {
if (explicitReceiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER) {
DeclarationDescriptor importableDescriptor = DescriptorUtilsKt.getImportableDescriptor(classDescriptor);
if (DescriptorUtils.getFqName(importableDescriptor).isSafe()) {
FqName fqName = getFqNameFromTopLevelClass(importableDescriptor);
String qualifiedName;
if (reference.getParent() instanceof KtCallableReferenceExpression) {
qualifiedName = fqName.parent() + "::" + classDescriptor.getName();
}
else {
qualifiedName = fqName.asString();
}
trace.report(NESTED_CLASS_SHOULD_BE_QUALIFIED.on(reference, classDescriptor, qualifiedName));
return;
}
}
trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(reference, classDescriptor));
}
@Override
public void unsafeCall(@NotNull BindingTrace trace, @NotNull KotlinType type, boolean isCallForImplicitInvoke) {
ASTNode callOperationNode = call.getCallOperationNode();
if (callOperationNode != null && !isCallForImplicitInvoke) {
trace.report(UNSAFE_CALL.on(callOperationNode.getPsi(), type));
}
else {
PsiElement callElement = call.getCallElement();
if (callElement instanceof KtBinaryExpression) {
reportUnsafeCallOnBinaryExpression(trace, (KtBinaryExpression) callElement);
}
else if (isCallForImplicitInvoke) {
trace.report(UNSAFE_IMPLICIT_INVOKE_CALL.on(reference, type));
}
else {
trace.report(UNSAFE_CALL.on(reference, type));
}
}
}
private void reportUnsafeCallOnBinaryExpression(@NotNull BindingTrace trace, @NotNull KtBinaryExpression binaryExpression) {
KtSimpleNameExpression operationReference = binaryExpression.getOperationReference();
boolean isInfixCall = operationReference.getReferencedNameElementType() == KtTokens.IDENTIFIER;
Name operationString = isInfixCall ?
Name.identifier(operationReference.getText()) :
OperatorConventions.getNameForOperationSymbol((KtToken) operationReference.getReferencedNameElementType());
if (operationString == null) return;
KtExpression left = binaryExpression.getLeft();
KtExpression right = binaryExpression.getRight();
if (left == null || right == null) return;
if (isInfixCall) {
trace.report(UNSAFE_INFIX_CALL.on(reference, left, operationString.asString(), right));
}
else {
boolean inOperation = KtPsiUtil.isInOrNotInOperation(binaryExpression);
KtExpression receiver = inOperation ? right : left;
KtExpression argument = inOperation ? left : right;
trace.report(UNSAFE_OPERATOR_CALL.on(reference, receiver, operationString.asString(), argument));
}
}
@Override
public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {
trace.report(INVISIBLE_MEMBER.on(call.getCallElement(), descriptor, descriptor.getVisibility(), descriptor));
}
@Override
public void typeInferenceFailed(@NotNull ResolutionContext> context, @NotNull InferenceErrorData data) {
Diagnostic diagnostic = typeInferenceFailedDiagnostic(context, data, reference, call);
if (diagnostic != null) {
context.trace.report(diagnostic);
}
}
@Nullable
public static Diagnostic typeInferenceFailedDiagnostic(
@NotNull ResolutionContext> context,
@NotNull InferenceErrorData data,
@NotNull KtExpression reference,
@NotNull Call call
) {
ConstraintSystem constraintSystem = data.constraintSystem;
ConstraintSystemStatus status = constraintSystem.getStatus();
assert !status.isSuccessful() : "Report error only for not successful constraint system";
if (status.hasErrorInConstrainingTypes()) {
// Do not report type inference errors if there is one in the arguments
// (it's useful, when the arguments, e.g. lambdas or calls are incomplete)
return null;
}
if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION)) {
KotlinType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return null;
ConstraintSystem systemWithoutExpectedTypeConstraint = filterConstraintsOut(constraintSystem, EXPECTED_TYPE_POSITION);
KotlinType substitutedReturnType = systemWithoutExpectedTypeConstraint.getResultingSubstitutor().substitute(
declaredReturnType, Variance.OUT_VARIANCE);
assert substitutedReturnType != null; //todo
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(
context, call.getCallElement(), data.expectedType, substitutedReturnType)) {
return TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(call.getCallElement(), data.expectedType, substitutedReturnType);
}
}
else if (status.hasCannotCaptureTypesError()) {
return TYPE_INFERENCE_CANNOT_CAPTURE_TYPES.on(reference, data);
}
else if (status.hasViolatedUpperBound()) {
return TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, data);
}
else if (status.hasParameterConstraintError()) {
return TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR.on(reference, data);
}
else if (status.hasConflictingConstraints()) {
return TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data);
}
else if (status.hasTypeInferenceIncorporationError()) {
return TYPE_INFERENCE_INCORPORATION_ERROR.on(reference);
}
else if (status.hasTypeParameterWithUnsatisfiedOnlyInputTypesError()) {
//todo
return TYPE_INFERENCE_ONLY_INPUT_TYPES.getErrorFactory().on(reference, data.descriptor.getTypeParameters().get(0));
}
else {
assert status.hasUnknownParameters();
return TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data);
}
return null;
}
}