Improve diagnostics for fake calls when type inference failed
#KT-13665 Fixed
This commit is contained in:
+27
-11
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -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()<!>
|
||||
}
|
||||
+11
@@ -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
|
||||
}
|
||||
+8
@@ -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()<!>) {
|
||||
}
|
||||
}
|
||||
+11
@@ -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");
|
||||
|
||||
+6
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user