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> { val ARGUMENT_TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("expectedType") parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType") parameter<ConeKotlinType>("actualType")
parameter<Boolean>("isMismatchDueToNullability")
} }
val NULL_FOR_NONNULL_TYPE by error<PsiElement> { } val NULL_FOR_NONNULL_TYPE by error<PsiElement> { }
@@ -235,7 +235,7 @@ object FirErrors {
val TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>() val TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val THROWABLE_TYPE_MISMATCH by error1<PsiElement, ConeKotlinType>() val THROWABLE_TYPE_MISMATCH by error1<PsiElement, ConeKotlinType>()
val CONDITION_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 NULL_FOR_NONNULL_TYPE by error0<PsiElement>()
val INAPPLICABLE_LATEINIT_MODIFIER by error1<KtModifierListOwner, String>(SourceElementPositioningStrategies.LATEINIT_MODIFIER) val INAPPLICABLE_LATEINIT_MODIFIER by error1<KtModifierListOwner, String>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
val VARARG_OUTSIDE_PARENTHESES by error0<KtExpression>() 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.FIR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FQ_NAMES_IN_TYPES 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.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.NULLABLE_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE 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(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(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(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(ASSIGNMENT_TYPE_MISMATCH, "Assignment type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
map.put( map.put(
RESULT_TYPE_MISMATCH, RESULT_TYPE_MISMATCH,
@@ -136,7 +136,8 @@ private fun mapInapplicableCandidateError(
is ArgumentTypeMismatch -> FirErrors.ARGUMENT_TYPE_MISMATCH.on( is ArgumentTypeMismatch -> FirErrors.ARGUMENT_TYPE_MISMATCH.on(
rootCause.argument.source ?: source, rootCause.argument.source ?: source,
rootCause.expectedType, rootCause.expectedType,
rootCause.actualType rootCause.actualType,
rootCause.isMismatchDueToNullability
) )
is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.on( is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.on(
rootCause.argument.source ?: source rootCause.argument.source ?: source
@@ -375,10 +375,18 @@ private fun checkApplicabilityForArgumentType(
return type 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( return ArgumentTypeMismatch(
tryGetConeTypeThatCompatibleWithKtType(actualExpectedType), tryGetConeTypeThatCompatibleWithKtType(actualExpectedType),
tryGetConeTypeThatCompatibleWithKtType(argumentType), tryGetConeTypeThatCompatibleWithKtType(argumentType),
argument argument,
isMismatchDueToNullability
) )
} }
@@ -93,7 +93,8 @@ sealed class UnstableSmartCast(
class ArgumentTypeMismatch( class ArgumentTypeMismatch(
val expectedType: ConeKotlinType, val expectedType: ConeKotlinType,
val actualType: ConeKotlinType, val actualType: ConeKotlinType,
val argument: FirExpression val argument: FirExpression,
val isMismatchDueToNullability: Boolean,
) : ResolutionDiagnostic(INAPPLICABLE) ) : ResolutionDiagnostic(INAPPLICABLE)
class NullForNotNullType( class NullForNotNullType(
@@ -961,6 +961,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
ArgumentTypeMismatchImpl( ArgumentTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b), firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic.c,
firDiagnostic as FirPsiDiagnostic<*>, firDiagnostic as FirPsiDiagnostic<*>,
token, token,
) )
@@ -688,6 +688,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ArgumentTypeMismatch::class override val diagnosticClass get() = ArgumentTypeMismatch::class
abstract val expectedType: KtType abstract val expectedType: KtType
abstract val actualType: KtType abstract val actualType: KtType
abstract val isMismatchDueToNullability: Boolean
} }
abstract class NullForNonnullType : KtFirDiagnostic<PsiElement>() { abstract class NullForNonnullType : KtFirDiagnostic<PsiElement>() {
@@ -1105,6 +1105,7 @@ internal class ConditionTypeMismatchImpl(
internal class ArgumentTypeMismatchImpl( internal class ArgumentTypeMismatchImpl(
override val expectedType: KtType, override val expectedType: KtType,
override val actualType: KtType, override val actualType: KtType,
override val isMismatchDueToNullability: Boolean,
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.ArgumentTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> { ) : KtFirDiagnostic.ArgumentTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {