[NI] Initial support of "not enough information" diagnostic

#KT-30590 In Progress
This commit is contained in:
Mikhail Zarechenskiy
2019-04-22 00:18:20 +03:00
parent c1b586f921
commit 09cc2ae27f
11 changed files with 62 additions and 6 deletions
@@ -10532,6 +10532,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/FunctionPlaceholder.kt");
}
@TestMetadata("inferTypeFromUnresolvedArgument.kt")
public void testInferTypeFromUnresolvedArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/inferTypeFromUnresolvedArgument.kt");
}
@TestMetadata("NoAmbiguityForDifferentFunctionTypes.kt")
public void testNoAmbiguityForDifferentFunctionTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt");
@@ -735,6 +735,8 @@ public interface Errors {
DiagnosticFactory0<KtParameter> CANNOT_INFER_PARAMETER_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR = DiagnosticFactory1.create(ERROR);
@@ -831,6 +831,8 @@ public class DefaultErrorMessages {
MAP.put(TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS, "Type inference failed: {0}", TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER);
MAP.put(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES, "Type inference failed: {0}", TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
MAP.put(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Not enough information to infer type variable {0}", STRING);
MAP.put(TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR, "Type inference failed: {0}", TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER);
MAP.put(TYPE_INFERENCE_INCORPORATION_ERROR, "Type inference failed. Please try to specify type arguments explicitly.");
MAP.put(TYPE_INFERENCE_ONLY_INPUT_TYPES, "Type inference failed. The value of the type parameter {0} should be mentioned in input types " +
@@ -32,7 +32,8 @@ class DiagnosticReporterByTrackingStrategy(
val constantExpressionEvaluator: ConstantExpressionEvaluator,
val context: BasicCallResolutionContext,
val psiKotlinCall: PSIKotlinCall,
val dataFlowValueFactory: DataFlowValueFactory
val dataFlowValueFactory: DataFlowValueFactory,
val allDiagnostics: List<KotlinCallDiagnostic>
) : DiagnosticReporter {
private val trace = context.trace as TrackingBindingTrace
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
@@ -245,6 +246,18 @@ class DiagnosticReporterByTrackingStrategy(
)
}
}
NotEnoughInformationForTypeParameter::class.java -> {
val error = diagnostic as NotEnoughInformationForTypeParameter
val call = error.resolvedAtom.atom?.safeAs<PSIKotlinCall>()?.psiCall ?: call
val expression = call.calleeExpression ?: return
val typeVariableName = when (val typeVariable = error.typeVariable) {
is TypeVariableFromCallableDescriptor -> typeVariable.originalTypeParameter.name.asString()
is TypeVariableForLambdaReturnType -> "return type of lambda"
else -> error("Unsupported type variable: $typeVariable")
}
trace.report(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(expression, typeVariableName))
}
}
}
@@ -423,13 +423,21 @@ class KotlinToResolvedCallTransformer(
) {
val trackingTrace = TrackingBindingTrace(trace)
val newContext = context.replaceBindingTrace(trackingTrace)
val diagnosticReporter =
DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall, context.dataFlowValueFactory)
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics)
for (diagnostic in diagnostics + diagnosticHolder.getDiagnostics()) {
val allDiagnostics = diagnostics + diagnosticHolder.getDiagnostics()
val diagnosticReporter = DiagnosticReporterByTrackingStrategy(
constantExpressionEvaluator,
newContext,
completedCallAtom.atom.psiKotlinCall,
context.dataFlowValueFactory,
allDiagnostics
)
for (diagnostic in allDiagnostics) {
trackingTrace.reported = false
diagnostic.report(diagnosticReporter)
@@ -87,7 +87,7 @@ class KotlinConstraintSystemCompleter(
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
if (!variableForFixation.hasProperConstraint) {
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable, topLevelAtoms.first()))
}
continue
}
@@ -101,7 +101,10 @@ class CapturedTypeFromSubtyping(
val position: ConstraintPosition
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class NotEnoughInformationForTypeParameter(val typeVariable: TypeVariableMarker) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class NotEnoughInformationForTypeParameter(
val typeVariable: TypeVariableMarker,
val resolvedAtom: ResolvedAtom
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class ConstrainingTypeIsError(
val typeVariable: TypeVariableMarker,
@@ -0,0 +1,9 @@
// !WITH_NEW_INFERENCE
// !DIAGNOSTICS: -UNUSED_PARAMETER
fun <K> id2(x: K, s: String): K = x
fun test() {
<!NI;IMPLICIT_NOTHING_AS_TYPE_PARAMETER, NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>id2<!>(<!UNRESOLVED_REFERENCE!>unresolved<!>, "foo")
<!NI;UNREACHABLE_CODE!><!NI;IMPLICIT_NOTHING_AS_TYPE_PARAMETER, NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>id2<!>(<!UNRESOLVED_REFERENCE!>unresolved<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!>)<!>
}
@@ -0,0 +1,4 @@
package
public fun </*0*/ K> id2(/*0*/ x: K, /*1*/ s: kotlin.String): K
public fun test(): kotlin.Unit
@@ -10539,6 +10539,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/FunctionPlaceholder.kt");
}
@TestMetadata("inferTypeFromUnresolvedArgument.kt")
public void testInferTypeFromUnresolvedArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/inferTypeFromUnresolvedArgument.kt");
}
@TestMetadata("NoAmbiguityForDifferentFunctionTypes.kt")
public void testNoAmbiguityForDifferentFunctionTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt");
@@ -10534,6 +10534,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/FunctionPlaceholder.kt");
}
@TestMetadata("inferTypeFromUnresolvedArgument.kt")
public void testInferTypeFromUnresolvedArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/inferTypeFromUnresolvedArgument.kt");
}
@TestMetadata("NoAmbiguityForDifferentFunctionTypes.kt")
public void testNoAmbiguityForDifferentFunctionTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt");