FIR: Implement more precise reporting diagnostics from new inference
This commit is contained in:
committed by
teamcityserver
parent
c67ae8a0a3
commit
c46d049394
+3
@@ -38,6 +38,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val UNSUPPORTED_FEATURE by error<PsiElement> {
|
||||
parameter<Pair<LanguageFeature, LanguageVersionSettings>>("unsupportedFeature")
|
||||
}
|
||||
val NEW_INFERENCE_ERROR by error<PsiElement> {
|
||||
parameter<String>("error")
|
||||
}
|
||||
}
|
||||
|
||||
val Miscellaneous by object : DiagnosticGroup("Miscellaneous") {
|
||||
|
||||
@@ -74,6 +74,7 @@ object FirErrors {
|
||||
// Meta-errors
|
||||
val UNSUPPORTED by error1<PsiElement, String>()
|
||||
val UNSUPPORTED_FEATURE by error1<PsiElement, Pair<LanguageFeature, LanguageVersionSettings>>()
|
||||
val NEW_INFERENCE_ERROR by error1<PsiElement, String>()
|
||||
|
||||
// Miscellaneous
|
||||
val SYNTAX by error0<PsiElement>()
|
||||
|
||||
+81
-3
@@ -15,10 +15,17 @@ 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.model.ConeArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -70,10 +77,11 @@ fun ConeDiagnostic.toFirDiagnostics(
|
||||
source: FirSourceElement,
|
||||
qualifiedAccessSource: FirSourceElement?
|
||||
): List<FirDiagnostic<FirSourceElement>> {
|
||||
if (this is ConeInapplicableCandidateError) {
|
||||
return mapInapplicableCandidateError(this, source, qualifiedAccessSource)
|
||||
return when (this) {
|
||||
is ConeInapplicableCandidateError -> mapInapplicableCandidateError(this, source, qualifiedAccessSource)
|
||||
is ConeConstraintSystemHasContradiction -> mapSystemHasContradictionError(this, source, qualifiedAccessSource)
|
||||
else -> listOfNotNull(toFirDiagnostic(source, qualifiedAccessSource))
|
||||
}
|
||||
return listOfNotNull(toFirDiagnostic(source, qualifiedAccessSource))
|
||||
}
|
||||
|
||||
private fun mapUnsafeCallError(
|
||||
@@ -150,6 +158,76 @@ private fun mapInapplicableCandidateError(
|
||||
}.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun mapSystemHasContradictionError(
|
||||
diagnostic: ConeConstraintSystemHasContradiction,
|
||||
source: FirSourceElement,
|
||||
qualifiedAccessSource: FirSourceElement?,
|
||||
): List<FirDiagnostic<FirSourceElement>> = buildList<FirDiagnostic<FirSourceElement>> {
|
||||
for (error in diagnostic.candidate.system.errors) {
|
||||
addIfNotNull(error.toDiagnostic(source, qualifiedAccessSource, diagnostic.candidate.callInfo.session.typeContext))
|
||||
}
|
||||
}.ifEmpty {
|
||||
listOfNotNull(
|
||||
diagnostic.candidate.system.errors.firstNotNullOfOrNull {
|
||||
val message = when (it) {
|
||||
is NewConstraintError -> "NewConstraintError at ${it.position}: ${it.lowerType} <!: ${it.upperType}"
|
||||
// Error should be reported on the error type itself
|
||||
is ConstrainingTypeIsError -> return@firstNotNullOfOrNull null
|
||||
else -> "Inference error: ${it::class.simpleName}"
|
||||
}
|
||||
FirErrors.NEW_INFERENCE_ERROR.on(qualifiedAccessSource ?: source, message)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun ConstraintSystemError.toDiagnostic(
|
||||
source: FirSourceElement,
|
||||
qualifiedAccessSource: FirSourceElement?,
|
||||
typeContext: ConeTypeContext,
|
||||
): FirDiagnostic<FirSourceElement>? = when (this) {
|
||||
is NewConstraintError -> {
|
||||
val position = position.from
|
||||
val argument =
|
||||
when (position) {
|
||||
// TODO: Support other ReceiverConstraintPositionImpl, LHSArgumentConstraintPositionImpl
|
||||
is ConeArgumentConstraintPosition -> position.argument
|
||||
is ConeLambdaArgumentConstraintPosition -> position.lambda
|
||||
else -> null
|
||||
}
|
||||
|
||||
argument?.let {
|
||||
return FirErrors.TYPE_MISMATCH.on(it.source ?: source, lowerConeType, upperConeType)
|
||||
}
|
||||
|
||||
when (position) {
|
||||
is ExpectedTypeConstraintPosition<*> -> {
|
||||
val inferredType =
|
||||
if (!lowerConeType.isNullableNothing)
|
||||
lowerConeType
|
||||
else
|
||||
upperConeType.withNullability(ConeNullability.NULLABLE, typeContext)
|
||||
|
||||
FirErrors.TYPE_MISMATCH.on(qualifiedAccessSource ?: source, upperConeType, inferredType)
|
||||
}
|
||||
is ExplicitTypeParameterConstraintPosition<*> -> {
|
||||
val conePosition = position as ConeExplicitTypeParameterConstraintPosition
|
||||
val typeArgument = conePosition.typeArgument
|
||||
|
||||
FirErrors.UPPER_BOUND_VIOLATED.on(
|
||||
typeArgument.source ?: qualifiedAccessSource ?: source,
|
||||
upperConeType,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val NewConstraintError.lowerConeType: ConeKotlinType get() = lowerType as ConeKotlinType
|
||||
private val NewConstraintError.upperConeType: ConeKotlinType get() = upperType as ConeKotlinType
|
||||
|
||||
private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagnosticFactory0<*> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (kind) {
|
||||
|
||||
+3
-2
@@ -13,13 +13,14 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeDeclaredUpperBoundConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||
|
||||
@@ -71,7 +72,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||
typeParameter,
|
||||
context.session
|
||||
).fullyExpandedType(context.session),
|
||||
SimpleConstraintSystemConstraintPosition // TODO
|
||||
ConeExplicitTypeParameterConstraintPosition(typeArgument)
|
||||
)
|
||||
is FirStarProjection -> csBuilder.addEqualityConstraint(
|
||||
freshVariable.defaultType,
|
||||
|
||||
+6
@@ -50,6 +50,12 @@ class ConeInapplicableCandidateError(
|
||||
override val reason: String get() = "Inapplicable($applicability): ${describeSymbol(candidate.symbol)}"
|
||||
}
|
||||
|
||||
class ConeConstraintSystemHasContradiction(
|
||||
val candidate: Candidate,
|
||||
) : ConeDiagnostic() {
|
||||
override val reason: String get() = "CS errors: ${describeSymbol(candidate.symbol)}"
|
||||
}
|
||||
|
||||
class ConeArgumentTypeMismatchCandidateError(
|
||||
val expectedType: ConeKotlinType, val actualType: ConeKotlinType
|
||||
) : ConeDiagnostic() {
|
||||
|
||||
+11
-6
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.inference
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||
@@ -12,10 +13,10 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeVariable
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeVariableType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.resolve.calls.model.LambdaWithTypeVariableAsExpectedTypeMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedCallableReferenceMarker
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
@@ -29,6 +30,7 @@ class ConeTypeVariableForPostponedAtom(name: String) : ConeTypeVariable(name)
|
||||
// -------------------------- Atoms --------------------------
|
||||
|
||||
sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker {
|
||||
abstract val atom: FirElement
|
||||
abstract override val inputTypes: Collection<ConeKotlinType>
|
||||
abstract override val outputType: ConeKotlinType?
|
||||
override var analyzed: Boolean = false
|
||||
@@ -38,7 +40,7 @@ sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker {
|
||||
// ------------- Lambdas -------------
|
||||
|
||||
class ResolvedLambdaAtom(
|
||||
val atom: FirAnonymousFunction,
|
||||
override val atom: FirAnonymousFunction,
|
||||
expectedType: ConeKotlinType?,
|
||||
val isSuspend: Boolean,
|
||||
val receiver: ConeKotlinType?,
|
||||
@@ -75,7 +77,7 @@ class ResolvedLambdaAtom(
|
||||
}
|
||||
|
||||
class LambdaWithTypeVariableAsExpectedTypeAtom(
|
||||
val atom: FirAnonymousFunction,
|
||||
override val atom: FirAnonymousFunction,
|
||||
private val initialExpectedTypeType: ConeKotlinType,
|
||||
val expectedTypeRef: FirTypeRef,
|
||||
val candidateOfOuterCall: Candidate,
|
||||
@@ -116,6 +118,9 @@ class ResolvedCallableReferenceAtom(
|
||||
private val session: FirSession
|
||||
) : PostponedResolvedAtom(), PostponedCallableReferenceMarker {
|
||||
|
||||
override val atom: FirCallableReferenceAccess
|
||||
get() = reference
|
||||
|
||||
var hasBeenResolvedOnce: Boolean = false
|
||||
var hasBeenPostponed: Boolean = false
|
||||
|
||||
|
||||
+15
-4
@@ -5,13 +5,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.inference.model
|
||||
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.FixVariableConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||
|
||||
class ConeDeclaredUpperBoundConstraintPosition : DeclaredUpperBoundConstraintPosition<Nothing?>(null)
|
||||
|
||||
class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVariableConstraintPosition<Nothing?>(variable, null)
|
||||
|
||||
class ConeArgumentConstraintPosition : ArgumentConstraintPosition<Nothing?>(null)
|
||||
class ConeArgumentConstraintPosition(argument: FirElement) : ArgumentConstraintPosition<FirElement>(argument)
|
||||
|
||||
class ConeExpectedTypeConstraintPosition : ExpectedTypeConstraintPosition<Nothing?>(null)
|
||||
|
||||
class ConeExplicitTypeParameterConstraintPosition(
|
||||
typeArgument: FirTypeProjection,
|
||||
) : ExplicitTypeParameterConstraintPosition<FirTypeProjection>(typeArgument)
|
||||
|
||||
class ConeLambdaArgumentConstraintPosition(
|
||||
anonymousFunction: FirAnonymousFunction
|
||||
) : LambdaArgumentConstraintPosition<FirAnonymousFunction>(anonymousFunction)
|
||||
|
||||
+10
-1
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeConstraintSystemHasContradiction
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.*
|
||||
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildStarProjection
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
@@ -739,7 +741,14 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
private fun FirNamedReferenceWithCandidate.toResolvedReference(): FirNamedReference {
|
||||
val errorDiagnostic = when {
|
||||
this is FirErrorReferenceWithCandidate -> this.diagnostic
|
||||
!candidate.isSuccessful -> ConeInapplicableCandidateError(candidate.currentApplicability, candidate)
|
||||
!candidate.currentApplicability.isSuccess -> ConeInapplicableCandidateError(candidate.currentApplicability, candidate)
|
||||
!candidate.isSuccessful -> {
|
||||
require(candidate.system.hasContradiction) {
|
||||
"Candidate is not successful, but system has no contradiction"
|
||||
}
|
||||
|
||||
ConeConstraintSystemHasContradiction(candidate)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -71,6 +71,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NEW_INFERENCE_ERROR) { firDiagnostic ->
|
||||
NewInferenceErrorImpl(
|
||||
firDiagnostic.a,
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.SYNTAX) { firDiagnostic ->
|
||||
SyntaxImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
|
||||
+5
@@ -74,6 +74,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val unsupportedFeature: Pair<LanguageFeature, LanguageVersionSettings>
|
||||
}
|
||||
|
||||
abstract class NewInferenceError : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = NewInferenceError::class
|
||||
abstract val error: String
|
||||
}
|
||||
|
||||
abstract class Syntax : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = Syntax::class
|
||||
}
|
||||
|
||||
+8
@@ -81,6 +81,14 @@ internal class UnsupportedFeatureImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NewInferenceErrorImpl(
|
||||
override val error: String,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NewInferenceError(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class SyntaxImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user