FIR: Report INFERENCE_NO_INFORMATION_FOR_PARAMETER diagnostic
This commit is contained in:
committed by
TeamCityServer
parent
6e901e3785
commit
c420957eac
+4
@@ -341,6 +341,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
}
|
||||
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
|
||||
|
||||
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error<KtElement> {
|
||||
parameter<String>("name")
|
||||
}
|
||||
}
|
||||
|
||||
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
|
||||
|
||||
@@ -256,6 +256,7 @@ object FirErrors {
|
||||
val ASSIGNMENT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
val RESULT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
||||
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
|
||||
|
||||
// Ambiguity
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+24
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.declarations.isOperator
|
||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeVariableForLambdaReturnType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
||||
@@ -191,6 +193,7 @@ private fun mapSystemHasContradictionError(
|
||||
qualifiedAccessSource,
|
||||
diagnostic.candidate.callInfo.session.typeContext,
|
||||
errorsToIgnore,
|
||||
diagnostic.candidate,
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -202,6 +205,7 @@ private fun mapSystemHasContradictionError(
|
||||
is NewConstraintError -> "NewConstraintError at ${it.position}: ${it.lowerType} <!: ${it.upperType}"
|
||||
// Error should be reported on the error type itself
|
||||
is ConstrainingTypeIsError -> return@firstNotNullOfOrNull null
|
||||
is NotEnoughInformationForTypeParameter<*> -> return@firstNotNullOfOrNull null
|
||||
else -> "Inference error: ${it::class.simpleName}"
|
||||
}
|
||||
|
||||
@@ -223,6 +227,7 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
qualifiedAccessSource: FirSourceElement?,
|
||||
typeContext: ConeTypeContext,
|
||||
errorsToIgnore: MutableSet<ConstraintSystemError>,
|
||||
candidate: Candidate,
|
||||
): FirDiagnostic<FirSourceElement>? {
|
||||
return when (this) {
|
||||
is NewConstraintError -> {
|
||||
@@ -270,6 +275,25 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
is NotEnoughInformationForTypeParameter<*> -> {
|
||||
val isDiagnosticRedundant = candidate.system.errors.any { otherError ->
|
||||
(otherError is ConstrainingTypeIsError && otherError.typeVariable == this.typeVariable)
|
||||
|| otherError is NewConstraintError
|
||||
}
|
||||
|
||||
if (isDiagnosticRedundant) return null
|
||||
|
||||
val typeVariableName = when (val typeVariable = this.typeVariable) {
|
||||
is ConeTypeParameterBasedTypeVariable -> typeVariable.typeParameterSymbol.name.asString()
|
||||
is ConeTypeVariableForLambdaReturnType -> "return type of lambda"
|
||||
else -> error("Unsupported type variable: $typeVariable")
|
||||
}
|
||||
|
||||
FirErrors.NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(
|
||||
source,
|
||||
typeVariableName,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ typealias ConeKotlinErrorType = ConeClassErrorType
|
||||
|
||||
class ConeClassLikeErrorLookupTag(override val classId: ClassId) : ConeClassLikeLookupTag()
|
||||
|
||||
class ConeClassErrorType(val diagnostic: ConeDiagnostic) : ConeClassLikeType() {
|
||||
class ConeClassErrorType(val diagnostic: ConeDiagnostic, val isUninferredParameter: Boolean = false) : ConeClassLikeType() {
|
||||
override val lookupTag: ConeClassLikeLookupTag
|
||||
get() = ConeClassLikeErrorLookupTag(ClassId.fromString("<error>"))
|
||||
|
||||
|
||||
+3
-2
@@ -99,8 +99,9 @@ object ConeConstraintSystemUtilContext : ConstraintSystemUtilContext {
|
||||
argument: PostponedAtomWithRevisableExpectedType,
|
||||
index: Int
|
||||
): TypeVariableMarker {
|
||||
return ConeTypeVariableForPostponedAtom(
|
||||
PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE + index
|
||||
return ConeTypeVariableForLambdaParameterType(
|
||||
PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE + index,
|
||||
index
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+76
-7
@@ -5,6 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.inference
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
@@ -15,10 +18,12 @@ import org.jetbrains.kotlin.fir.returnExpressions
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
@@ -219,19 +224,83 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
||||
fixVariable(asConstraintSystemCompletionContext(), topLevelType, variableWithConstraints, postponedArguments)
|
||||
return true
|
||||
} else {
|
||||
// TODO("Not enough information for parameter")
|
||||
fixVariable(
|
||||
asConstraintSystemCompletionContext(),
|
||||
topLevelType,
|
||||
variableWithConstraints,
|
||||
postponedArguments
|
||||
) // means Nothing/Any instead of Error type
|
||||
processVariableWhenNotEnoughInformation(this, variableWithConstraints, topLevelAtoms)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun processVariableWhenNotEnoughInformation(
|
||||
c: ConstraintSystemCompletionContext,
|
||||
variableWithConstraints: VariableWithConstraints,
|
||||
topLevelAtoms: List<FirStatement>,
|
||||
) {
|
||||
val typeVariable = variableWithConstraints.typeVariable
|
||||
val resolvedAtom =
|
||||
findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
|
||||
|
||||
if (resolvedAtom != null) {
|
||||
c.addError(NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom))
|
||||
}
|
||||
|
||||
val resultErrorType = when (typeVariable) {
|
||||
is ConeTypeParameterBasedTypeVariable ->
|
||||
createCannotInferErrorType(
|
||||
"Cannot infer argument for type parameter ${typeVariable.typeParameterSymbol.name}",
|
||||
isUninferredParameter = true,
|
||||
)
|
||||
is ConeTypeVariableForLambdaParameterType -> createCannotInferErrorType("Cannot infer lambda parameter type")
|
||||
else -> createCannotInferErrorType("Cannot infer type variable $typeVariable")
|
||||
}
|
||||
|
||||
c.fixVariable(typeVariable, resultErrorType, ConeFixVariableConstraintPosition(typeVariable))
|
||||
}
|
||||
|
||||
private fun createCannotInferErrorType(message: String, isUninferredParameter: Boolean = false) =
|
||||
ConeClassErrorType(
|
||||
ConeSimpleDiagnostic(
|
||||
message,
|
||||
DiagnosticKind.CannotInferParameterType,
|
||||
),
|
||||
isUninferredParameter,
|
||||
)
|
||||
|
||||
private fun findResolvedAtomBy(
|
||||
typeVariable: TypeVariableMarker,
|
||||
topLevelAtoms: List<FirStatement>
|
||||
): FirStatement? {
|
||||
|
||||
fun FirStatement.findFirstAtomContainingVariable(): FirStatement? {
|
||||
|
||||
var result: FirStatement? = null
|
||||
|
||||
fun suggestElement(element: FirElement) {
|
||||
if (result == null && element is FirStatement) {
|
||||
result = element
|
||||
}
|
||||
}
|
||||
|
||||
this@findFirstAtomContainingVariable.processAllContainingCallCandidates(processBlocks = true) { candidate ->
|
||||
if (typeVariable in candidate.freshVariables) {
|
||||
suggestElement(candidate.callInfo.callSite)
|
||||
}
|
||||
|
||||
for (postponedAtom in candidate.postponedAtoms) {
|
||||
if (postponedAtom is ResolvedLambdaAtom) {
|
||||
if (postponedAtom.typeVariableForLambdaReturnType == typeVariable) {
|
||||
suggestElement(postponedAtom.atom)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return topLevelAtoms.firstNotNullOfOrNull(FirStatement::findFirstAtomContainingVariable)
|
||||
}
|
||||
|
||||
private fun analyzeRemainingNotAnalyzedPostponedArgument(
|
||||
postponedArguments: List<PostponedResolvedAtom>,
|
||||
analyze: (PostponedResolvedAtom) -> Unit
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
|
||||
class ConeTypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name)
|
||||
class ConeTypeVariableForPostponedAtom(name: String) : ConeTypeVariable(name)
|
||||
class ConeTypeVariableForLambdaParameterType(name: String, val index: Int) : ConeTypeVariable(name)
|
||||
|
||||
// -------------------------- Atoms --------------------------
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
|
||||
override fun KotlinTypeMarker.isUninferredParameter(): Boolean {
|
||||
assert(this is ConeKotlinType)
|
||||
return false // TODO
|
||||
return this is ConeClassErrorType && this.isUninferredParameter
|
||||
}
|
||||
|
||||
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
||||
|
||||
Reference in New Issue
Block a user