Improve diagnostics for fake calls when type inference failed

#KT-13665 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-08-31 14:55:07 +03:00
parent 17b4874c37
commit f5222600d8
8 changed files with 94 additions and 11 deletions
@@ -20,7 +20,9 @@ import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens;
@@ -215,6 +217,19 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
@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";
@@ -222,12 +237,11 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
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;
return null;
}
BindingTrace trace = context.trace;
if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION)) {
KotlinType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return;
if (declaredReturnType == null) return null;
ConstraintSystem systemWithoutExpectedTypeConstraint = filterConstraintsOut(constraintSystem, EXPECTED_TYPE_POSITION);
KotlinType substitutedReturnType = systemWithoutExpectedTypeConstraint.getResultingSubstitutor().substitute(
@@ -237,31 +251,33 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
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)) {
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(call.getCallElement(), data.expectedType, substitutedReturnType));
return TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(call.getCallElement(), data.expectedType, substitutedReturnType);
}
}
else if (status.hasCannotCaptureTypesError()) {
trace.report(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES.on(reference, data));
return TYPE_INFERENCE_CANNOT_CAPTURE_TYPES.on(reference, data);
}
else if (status.hasViolatedUpperBound()) {
trace.report(TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, data));
return TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(reference, data);
}
else if (status.hasParameterConstraintError()) {
trace.report(TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR.on(reference, data));
return TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR.on(reference, data);
}
else if (status.hasConflictingConstraints()) {
trace.report(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data));
return TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS.on(reference, data);
}
else if (status.hasTypeInferenceIncorporationError()) {
trace.report(TYPE_INFERENCE_INCORPORATION_ERROR.on(reference));
return TYPE_INFERENCE_INCORPORATION_ERROR.on(reference);
}
else if (status.hasTypeParameterWithUnsatisfiedOnlyInputTypesError()) {
//todo
trace.report(TYPE_INFERENCE_ONLY_INPUT_TYPES.on(reference, data.descriptor.getTypeParameters().get(0)));
return TYPE_INFERENCE_ONLY_INPUT_TYPES.on(reference, data.descriptor.getTypeParameters().get(0));
}
else {
assert status.hasUnknownParameters();
trace.report(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data));
return TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(reference, data);
}
return null;
}
}
@@ -27,8 +27,10 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.tasks.AbstractTracingStrategy
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
@@ -94,6 +96,13 @@ class FakeCallResolver(
override fun unsafeCall(trace: BindingTrace, type: KotlinType, isCallForImplicitInvoke: Boolean) {
trace.report(Errors.COMPONENT_FUNCTION_ON_NULLABLE.on(reportErrorsOn, name))
}
override fun typeInferenceFailed(context: ResolutionContext<*>, inferenceErrorData: InferenceErrorData) {
val diagnostic = AbstractTracingStrategy.typeInferenceFailedDiagnostic(context, inferenceErrorData, reportErrorsOn, call)
if (diagnostic != null) {
context.trace.report(diagnostic)
}
}
}
}
@@ -110,6 +119,13 @@ class FakeCallResolver(
override fun unsafeCall(trace: BindingTrace, type: KotlinType, isCallForImplicitInvoke: Boolean) {
trace.report(Errors.ITERATOR_ON_NULLABLE.on(reportErrorsOn))
}
override fun typeInferenceFailed(context: ResolutionContext<*>, inferenceErrorData: InferenceErrorData) {
val diagnostic = AbstractTracingStrategy.typeInferenceFailedDiagnostic(context, inferenceErrorData, reportErrorsOn, call)
if (diagnostic != null) {
context.trace.report(diagnostic)
}
}
}
}
@@ -0,0 +1,9 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
class X
operator fun <T> X.component1(): T = TODO()
fun test() {
val (y) = <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>X()<!>
}
@@ -0,0 +1,11 @@
package
public fun test(): kotlin.Unit
public operator fun </*0*/ T> X.component1(): T
public final class X {
public constructor X()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,8 @@
class X
operator fun <T> X.iterator(): Iterable<T> = TODO()
fun test() {
for (i in <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>X()<!>) {
}
}
@@ -0,0 +1,11 @@
package
public fun test(): kotlin.Unit
public operator fun </*0*/ T> X.iterator(): kotlin.collections.Iterable<T>
public final class X {
public constructor X()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -11046,6 +11046,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("typeInferenceFailedOnIteratorCall.kt")
public void testTypeInferenceFailedOnIteratorCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.kt");
doTest(fileName);
}
@TestMetadata("wrongArgumentExtensionFunction.kt")
public void testWrongArgumentExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/wrongArgumentExtensionFunction.kt");
@@ -11046,6 +11046,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
doTest(fileName);
}
@TestMetadata("typeInferenceFailedOnIteratorCall.kt")
public void testTypeInferenceFailedOnIteratorCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.kt");
doTest(fileName);
}
@TestMetadata("wrongArgumentExtensionFunction.kt")
public void testWrongArgumentExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/wrongArgumentExtensionFunction.kt");