diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 8a11ad2ad4f..db29c68814e 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -288,6 +288,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val ARGUMENT_TYPE_MISMATCH by error { parameter("expectedType") parameter("actualType") + parameter("isMismatchDueToNullability") } val NULL_FOR_NONNULL_TYPE by error { } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 1d0a3cf7959..0ff05736234 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -235,7 +235,7 @@ object FirErrors { val TYPE_MISMATCH by error2() val THROWABLE_TYPE_MISMATCH by error1() val CONDITION_TYPE_MISMATCH by error1() - val ARGUMENT_TYPE_MISMATCH by error2() + val ARGUMENT_TYPE_MISMATCH by error3() val NULL_FOR_NONNULL_TYPE by error0() val INAPPLICABLE_LATEINIT_MODIFIER by error1(SourceElementPositioningStrategies.LATEINIT_MODIFIER) val VARARG_OUTSIDE_PARENTHESES by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 9b3a2691232..069f340d88c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -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, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index b019f97d3d4..f38a3fb4e20 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -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 diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index b31beaf5dab..30dd9e6aee1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -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 ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index 7f661e02aa3..301e342c9d8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -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( diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index d1ee8ec655b..852c75e7e60 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -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, ) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index d42f2d0c38c..0a2f2ff65b2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -688,6 +688,7 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ArgumentTypeMismatch::class abstract val expectedType: KtType abstract val actualType: KtType + abstract val isMismatchDueToNullability: Boolean } abstract class NullForNonnullType : KtFirDiagnostic() { diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 22335abc2d9..a0e9dcdd4e9 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -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 {