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.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt; import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
@@ -215,6 +217,19 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
@Override @Override
public void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData data) { 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; ConstraintSystem constraintSystem = data.constraintSystem;
ConstraintSystemStatus status = constraintSystem.getStatus(); ConstraintSystemStatus status = constraintSystem.getStatus();
assert !status.isSuccessful() : "Report error only for not successful constraint system"; assert !status.isSuccessful() : "Report error only for not successful constraint system";
@@ -222,12 +237,11 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
if (status.hasErrorInConstrainingTypes()) { if (status.hasErrorInConstrainingTypes()) {
// Do not report type inference errors if there is one in the arguments // 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) // (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)) { if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION)) {
KotlinType declaredReturnType = data.descriptor.getReturnType(); KotlinType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return; if (declaredReturnType == null) return null;
ConstraintSystem systemWithoutExpectedTypeConstraint = filterConstraintsOut(constraintSystem, EXPECTED_TYPE_POSITION); ConstraintSystem systemWithoutExpectedTypeConstraint = filterConstraintsOut(constraintSystem, EXPECTED_TYPE_POSITION);
KotlinType substitutedReturnType = systemWithoutExpectedTypeConstraint.getResultingSubstitutor().substitute( 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"; assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection( if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(
context, call.getCallElement(), data.expectedType, substitutedReturnType)) { 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()) { 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()) { 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()) { 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()) { 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()) { else if (status.hasTypeInferenceIncorporationError()) {
trace.report(TYPE_INFERENCE_INCORPORATION_ERROR.on(reference)); return TYPE_INFERENCE_INCORPORATION_ERROR.on(reference);
} }
else if (status.hasTypeParameterWithUnsatisfiedOnlyInputTypesError()) { else if (status.hasTypeParameterWithUnsatisfiedOnlyInputTypesError()) {
//todo //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 { else {
assert status.hasUnknownParameters(); 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.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext 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.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults 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.TracingStrategy
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
@@ -94,6 +96,13 @@ class FakeCallResolver(
override fun unsafeCall(trace: BindingTrace, type: KotlinType, isCallForImplicitInvoke: Boolean) { override fun unsafeCall(trace: BindingTrace, type: KotlinType, isCallForImplicitInvoke: Boolean) {
trace.report(Errors.COMPONENT_FUNCTION_ON_NULLABLE.on(reportErrorsOn, name)) 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) { override fun unsafeCall(trace: BindingTrace, type: KotlinType, isCallForImplicitInvoke: Boolean) {
trace.report(Errors.ITERATOR_ON_NULLABLE.on(reportErrorsOn)) 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); 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") @TestMetadata("wrongArgumentExtensionFunction.kt")
public void testWrongArgumentExtensionFunction() throws Exception { public void testWrongArgumentExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/wrongArgumentExtensionFunction.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/wrongArgumentExtensionFunction.kt");
@@ -11046,6 +11046,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
doTest(fileName); 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") @TestMetadata("wrongArgumentExtensionFunction.kt")
public void testWrongArgumentExtensionFunction() throws Exception { public void testWrongArgumentExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/wrongArgumentExtensionFunction.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inference/reportingImprovements/wrongArgumentExtensionFunction.kt");