From f5222600d8520121a5e1f3dabd870c223eecfe99 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Thu, 31 Aug 2017 14:55:07 +0300 Subject: [PATCH] Improve diagnostics for fake calls when type inference failed #KT-13665 Fixed --- .../calls/tasks/AbstractTracingStrategy.java | 38 +++++++++++++------ .../types/expressions/FakeCallResolver.kt | 16 ++++++++ .../typeInferenceFailedOnComponentN.kt | 9 +++++ .../typeInferenceFailedOnComponentN.txt | 11 ++++++ .../typeInferenceFailedOnIteratorCall.kt | 8 ++++ .../typeInferenceFailedOnIteratorCall.txt | 11 ++++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ .../DiagnosticsUsingJavacTestGenerated.java | 6 +++ 8 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.kt create mode 100644 compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.txt create mode 100644 compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.kt create mode 100644 compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java index 2ba97de6b22..3b2ae430de1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java @@ -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; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt index ef7923059aa..0378af4cc03 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FakeCallResolver.kt @@ -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) + } + } } } diff --git a/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.kt b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.kt new file mode 100644 index 00000000000..4a222df93bb --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.kt @@ -0,0 +1,9 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + +class X + +operator fun X.component1(): T = TODO() + +fun test() { + val (y) = X() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.txt b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.txt new file mode 100644 index 00000000000..acf8a3bbc3a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnComponentN.txt @@ -0,0 +1,11 @@ +package + +public fun test(): kotlin.Unit +public operator fun 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 +} diff --git a/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.kt b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.kt new file mode 100644 index 00000000000..38d52e18f2a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.kt @@ -0,0 +1,8 @@ +class X + +operator fun X.iterator(): Iterable = TODO() + +fun test() { + for (i in X()) { + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.txt b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.txt new file mode 100644 index 00000000000..9c00f0a20ca --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/reportingImprovements/typeInferenceFailedOnIteratorCall.txt @@ -0,0 +1,11 @@ +package + +public fun test(): kotlin.Unit +public operator fun X.iterator(): kotlin.collections.Iterable + +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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index b086aa3e152..7d52797fe5f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 8e57fc675cc..4bb5766a009 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -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");