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.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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);
|
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");
|
||||||
|
|||||||
+6
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user