[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"); 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") @TestMetadata("NoAmbiguityForDifferentFunctionTypes.kt")
public void testNoAmbiguityForDifferentFunctionTypes() throws Exception { public void testNoAmbiguityForDifferentFunctionTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt"); 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); DiagnosticFactory0<KtParameter> CANNOT_INFER_PARAMETER_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.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_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = 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); 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_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_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(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_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_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 " + 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 constantExpressionEvaluator: ConstantExpressionEvaluator,
val context: BasicCallResolutionContext, val context: BasicCallResolutionContext,
val psiKotlinCall: PSIKotlinCall, val psiKotlinCall: PSIKotlinCall,
val dataFlowValueFactory: DataFlowValueFactory val dataFlowValueFactory: DataFlowValueFactory,
val allDiagnostics: List<KotlinCallDiagnostic>
) : DiagnosticReporter { ) : DiagnosticReporter {
private val trace = context.trace as TrackingBindingTrace private val trace = context.trace as TrackingBindingTrace
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy 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 trackingTrace = TrackingBindingTrace(trace)
val newContext = context.replaceBindingTrace(trackingTrace) val newContext = context.replaceBindingTrace(trackingTrace)
val diagnosticReporter =
DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall, context.dataFlowValueFactory)
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics) 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 trackingTrace.reported = false
diagnostic.report(diagnosticReporter) diagnostic.report(diagnosticReporter)
@@ -87,7 +87,7 @@ class KotlinConstraintSystemCompleter(
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives) fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
if (!variableForFixation.hasProperConstraint) { if (!variableForFixation.hasProperConstraint) {
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable)) c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable, topLevelAtoms.first()))
} }
continue continue
} }
@@ -101,7 +101,10 @@ class CapturedTypeFromSubtyping(
val position: ConstraintPosition val position: ConstraintPosition
) : ConstraintSystemCallDiagnostic(INAPPLICABLE) ) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class NotEnoughInformationForTypeParameter(val typeVariable: TypeVariableMarker) : ConstraintSystemCallDiagnostic(INAPPLICABLE) class NotEnoughInformationForTypeParameter(
val typeVariable: TypeVariableMarker,
val resolvedAtom: ResolvedAtom
) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class ConstrainingTypeIsError( class ConstrainingTypeIsError(
val typeVariable: TypeVariableMarker, 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"); 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") @TestMetadata("NoAmbiguityForDifferentFunctionTypes.kt")
public void testNoAmbiguityForDifferentFunctionTypes() throws Exception { public void testNoAmbiguityForDifferentFunctionTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt"); 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"); 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") @TestMetadata("NoAmbiguityForDifferentFunctionTypes.kt")
public void testNoAmbiguityForDifferentFunctionTypes() throws Exception { public void testNoAmbiguityForDifferentFunctionTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt"); runTest("compiler/testData/diagnostics/tests/inference/reportingImprovements/NoAmbiguityForDifferentFunctionTypes.kt");