FIR: store in ARGUMENT_TYPE_MISMATCH whether it's due to nullability

This commit is contained in:
Tianyu Geng
2021-04-30 20:48:09 +02:00
committed by Ilya Kirillov
parent cceb7197a5
commit 9106ae4f5f
9 changed files with 20 additions and 5 deletions
@@ -288,6 +288,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val ARGUMENT_TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
parameter<Boolean>("isMismatchDueToNullability")
}
val NULL_FOR_NONNULL_TYPE by error<PsiElement> { }
@@ -235,7 +235,7 @@ object FirErrors {
val TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val THROWABLE_TYPE_MISMATCH by error1<PsiElement, ConeKotlinType>()
val CONDITION_TYPE_MISMATCH by error1<PsiElement, ConeKotlinType>()
val ARGUMENT_TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val ARGUMENT_TYPE_MISMATCH by error3<PsiElement, ConeKotlinType, ConeKotlinType, Boolean>()
val NULL_FOR_NONNULL_TYPE by error0<PsiElement>()
val INAPPLICABLE_LATEINIT_MODIFIER by error1<KtModifierListOwner, String>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
val VARARG_OUTSIDE_PARENTHESES by error0<KtExpression>()
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.DECL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FIR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FQ_NAMES_IN_TYPES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NOT_RENDERED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
@@ -563,7 +564,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING)
map.put(THROWABLE_TYPE_MISMATCH, "Throwable type mismatch: actual type is {0}", TO_STRING)
map.put(CONDITION_TYPE_MISMATCH, "Condition type mismatch: inferred type is {0} but Boolean was expected", TO_STRING)
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE, NOT_RENDERED)
map.put(ASSIGNMENT_TYPE_MISMATCH, "Assignment type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
map.put(
RESULT_TYPE_MISMATCH,
@@ -136,7 +136,8 @@ private fun mapInapplicableCandidateError(
is ArgumentTypeMismatch -> FirErrors.ARGUMENT_TYPE_MISMATCH.on(
rootCause.argument.source ?: source,
rootCause.expectedType,
rootCause.actualType
rootCause.actualType,
rootCause.isMismatchDueToNullability
)
is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.on(
rootCause.argument.source ?: source
@@ -375,10 +375,18 @@ private fun checkApplicabilityForArgumentType(
return type
}
// Reaching here means argument types mismatch, and we want to record whether it's due to the nullability by checking a subtype
// relation with nullable expected type.
val isMismatchDueToNullability = AbstractTypeChecker.isSubtypeOf(
context.session.typeContext,
argumentType,
actualExpectedType.withNullability(ConeNullability.NULLABLE, context.session.typeContext)
)
return ArgumentTypeMismatch(
tryGetConeTypeThatCompatibleWithKtType(actualExpectedType),
tryGetConeTypeThatCompatibleWithKtType(argumentType),
argument
argument,
isMismatchDueToNullability
)
}
@@ -93,7 +93,8 @@ sealed class UnstableSmartCast(
class ArgumentTypeMismatch(
val expectedType: ConeKotlinType,
val actualType: ConeKotlinType,
val argument: FirExpression
val argument: FirExpression,
val isMismatchDueToNullability: Boolean,
) : ResolutionDiagnostic(INAPPLICABLE)
class NullForNotNullType(
@@ -961,6 +961,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
ArgumentTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic.c,
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
@@ -688,6 +688,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ArgumentTypeMismatch::class
abstract val expectedType: KtType
abstract val actualType: KtType
abstract val isMismatchDueToNullability: Boolean
}
abstract class NullForNonnullType : KtFirDiagnostic<PsiElement>() {
@@ -1105,6 +1105,7 @@ internal class ConditionTypeMismatchImpl(
internal class ArgumentTypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
override val isMismatchDueToNullability: Boolean,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ArgumentTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {