FIR checker: record whether type mismatch is due to nullability
This is useful for downstream quickfixes.
This commit is contained in:
committed by
teamcityserver
parent
d3e8cc577c
commit
951812f130
+1
-1
@@ -36,7 +36,7 @@ internal class KtFirBuiltInTypes(builtinTypes: BuiltinTypes, builder: KtSymbolBy
|
||||
override val NOTHING: KtType by cachedBuiltin(builtinTypes.nothingType)
|
||||
override val ANY: KtType by cachedBuiltin(builtinTypes.anyType)
|
||||
|
||||
|
||||
override val THROWABLE: KtType by cachedBuiltin(builtinTypes.throwableType)
|
||||
override val NULLABLE_ANY: KtType by cachedBuiltin(builtinTypes.nullableAnyType)
|
||||
override val NULLABLE_NOTHING: KtType by cachedBuiltin(builtinTypes.nullableNothingType)
|
||||
|
||||
|
||||
+7
@@ -1255,6 +1255,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
TypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
||||
firDiagnostic.c,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
@@ -1262,6 +1263,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
add(FirErrors.THROWABLE_TYPE_MISMATCH) { firDiagnostic ->
|
||||
ThrowableTypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firDiagnostic.b,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
@@ -1269,6 +1271,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
add(FirErrors.CONDITION_TYPE_MISMATCH) { firDiagnostic ->
|
||||
ConditionTypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firDiagnostic.b,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
@@ -1345,6 +1348,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
AssignmentTypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
||||
firDiagnostic.c,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
@@ -1711,6 +1715,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.c),
|
||||
firDiagnostic.d,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
@@ -1780,6 +1785,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firDiagnostic.b.source!!.psi as KtExpression,
|
||||
firDiagnostic.c,
|
||||
firDiagnostic.d,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
@@ -2416,6 +2422,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
InitializerTypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
||||
firDiagnostic.c,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
|
||||
+7
@@ -904,16 +904,19 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = TypeMismatch::class
|
||||
abstract val expectedType: KtType
|
||||
abstract val actualType: KtType
|
||||
abstract val isMismatchDueToNullability: Boolean
|
||||
}
|
||||
|
||||
abstract class ThrowableTypeMismatch : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = ThrowableTypeMismatch::class
|
||||
abstract val actualType: KtType
|
||||
abstract val isMismatchDueToNullability: Boolean
|
||||
}
|
||||
|
||||
abstract class ConditionTypeMismatch : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = ConditionTypeMismatch::class
|
||||
abstract val actualType: KtType
|
||||
abstract val isMismatchDueToNullability: Boolean
|
||||
}
|
||||
|
||||
abstract class ArgumentTypeMismatch : KtFirDiagnostic<PsiElement>() {
|
||||
@@ -968,6 +971,7 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = AssignmentTypeMismatch::class
|
||||
abstract val expectedType: KtType
|
||||
abstract val actualType: KtType
|
||||
abstract val isMismatchDueToNullability: Boolean
|
||||
}
|
||||
|
||||
abstract class ResultTypeMismatch : KtFirDiagnostic<KtExpression>() {
|
||||
@@ -1216,6 +1220,7 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val expectedType: KtType
|
||||
abstract val actualType: KtType
|
||||
abstract val targetFunction: KtSymbol
|
||||
abstract val isMismatchDueToNullability: Boolean
|
||||
}
|
||||
|
||||
abstract class CyclicGenericUpperBound : KtFirDiagnostic<PsiElement>() {
|
||||
@@ -1267,6 +1272,7 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val desiredType: KtType
|
||||
abstract val subject: KtExpression
|
||||
abstract val description: String
|
||||
abstract val isCastToNotNull: Boolean
|
||||
}
|
||||
|
||||
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
||||
@@ -1709,6 +1715,7 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = InitializerTypeMismatch::class
|
||||
abstract val expectedType: KtType
|
||||
abstract val actualType: KtType
|
||||
abstract val isMismatchDueToNullability: Boolean
|
||||
}
|
||||
|
||||
abstract class GetterVisibilityDiffersFromPropertyVisibility : KtFirDiagnostic<KtModifierListOwner>() {
|
||||
|
||||
+7
@@ -1438,6 +1438,7 @@ internal class InapplicableCandidateImpl(
|
||||
internal class TypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
override val isMismatchDueToNullability: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
@@ -1446,6 +1447,7 @@ internal class TypeMismatchImpl(
|
||||
|
||||
internal class ThrowableTypeMismatchImpl(
|
||||
override val actualType: KtType,
|
||||
override val isMismatchDueToNullability: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ThrowableTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
@@ -1454,6 +1456,7 @@ internal class ThrowableTypeMismatchImpl(
|
||||
|
||||
internal class ConditionTypeMismatchImpl(
|
||||
override val actualType: KtType,
|
||||
override val isMismatchDueToNullability: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ConditionTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
@@ -1541,6 +1544,7 @@ internal class NamedParameterNotFoundImpl(
|
||||
internal class AssignmentTypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
override val isMismatchDueToNullability: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.AssignmentTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
@@ -1951,6 +1955,7 @@ internal class ReturnTypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
override val targetFunction: KtSymbol,
|
||||
override val isMismatchDueToNullability: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ReturnTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
@@ -2029,6 +2034,7 @@ internal class SmartcastImpossibleImpl(
|
||||
override val desiredType: KtType,
|
||||
override val subject: KtExpression,
|
||||
override val description: String,
|
||||
override val isCastToNotNull: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.SmartcastImpossible(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
@@ -2747,6 +2753,7 @@ internal class WrongSetterParameterTypeImpl(
|
||||
internal class InitializerTypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
override val isMismatchDueToNullability: Boolean,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.InitializerTypeMismatch(), KtAbstractFirDiagnostic<KtProperty> {
|
||||
|
||||
+2
@@ -96,6 +96,8 @@ public abstract class KtBuiltinTypes : ValidityTokenOwner {
|
||||
public abstract val NOTHING: KtType
|
||||
public abstract val ANY: KtType
|
||||
|
||||
public abstract val THROWABLE: KtType
|
||||
|
||||
public abstract val NULLABLE_ANY: KtType
|
||||
public abstract val NULLABLE_NOTHING: KtType
|
||||
}
|
||||
|
||||
+7
@@ -401,14 +401,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val TYPE_MISMATCH by error<PsiElement> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
parameter<Boolean>("isMismatchDueToNullability")
|
||||
}
|
||||
|
||||
val THROWABLE_TYPE_MISMATCH by error<PsiElement> {
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
parameter<Boolean>("isMismatchDueToNullability")
|
||||
}
|
||||
|
||||
val CONDITION_TYPE_MISMATCH by error<PsiElement> {
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
parameter<Boolean>("isMismatchDueToNullability")
|
||||
}
|
||||
|
||||
val ARGUMENT_TYPE_MISMATCH by error<PsiElement> {
|
||||
@@ -446,6 +449,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ASSIGNMENT_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
parameter<Boolean>("isMismatchDueToNullability")
|
||||
}
|
||||
|
||||
val RESULT_TYPE_MISMATCH by error<KtExpression> {
|
||||
@@ -579,6 +583,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
parameter<FirSimpleFunction>("targetFunction")
|
||||
parameter<Boolean>("isMismatchDueToNullability")
|
||||
}
|
||||
|
||||
val CYCLIC_GENERIC_UPPER_BOUND by error<PsiElement>()
|
||||
@@ -617,6 +622,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("desiredType")
|
||||
parameter<FirExpression>("subject")
|
||||
parameter<String>("description")
|
||||
parameter<Boolean>("isCastToNotNull")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,6 +880,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val INITIALIZER_TYPE_MISMATCH by error<KtProperty>(PositioningStrategy.PROPERTY_INITIALIZER) {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
parameter<Boolean>("isMismatchDueToNullability")
|
||||
}
|
||||
val GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY by error<KtModifierListOwner>(PositioningStrategy.VISIBILITY_MODIFIER)
|
||||
val SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY by error<KtModifierListOwner>(PositioningStrategy.VISIBILITY_MODIFIER)
|
||||
|
||||
+7
-7
@@ -300,9 +300,9 @@ object FirErrors {
|
||||
// Applicability
|
||||
val NONE_APPLICABLE by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val INAPPLICABLE_CANDIDATE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
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 TYPE_MISMATCH by error3<PsiElement, ConeKotlinType, ConeKotlinType, Boolean>()
|
||||
val THROWABLE_TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, Boolean>()
|
||||
val CONDITION_TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, Boolean>()
|
||||
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)
|
||||
@@ -313,7 +313,7 @@ object FirErrors {
|
||||
val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableSymbol<*>>()
|
||||
val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameterSymbol>(SourceElementPositioningStrategies.VALUE_ARGUMENTS)
|
||||
val NAMED_PARAMETER_NOT_FOUND by error1<KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
|
||||
val ASSIGNMENT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
val ASSIGNMENT_TYPE_MISMATCH by error3<KtExpression, ConeKotlinType, ConeKotlinType, Boolean>()
|
||||
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>()
|
||||
@@ -368,7 +368,7 @@ object FirErrors {
|
||||
val REIFIED_TYPE_PARAMETER_NO_INLINE by error0<KtTypeParameter>(SourceElementPositioningStrategies.REIFIED_MODIFIER)
|
||||
val TYPE_PARAMETERS_NOT_ALLOWED by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
||||
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error0<KtTypeParameter>()
|
||||
val RETURN_TYPE_MISMATCH by error3<KtExpression, ConeKotlinType, ConeKotlinType, FirSimpleFunction>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
|
||||
val RETURN_TYPE_MISMATCH by error4<KtExpression, ConeKotlinType, ConeKotlinType, FirSimpleFunction, Boolean>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
|
||||
val CYCLIC_GENERIC_UPPER_BOUND by error0<PsiElement>()
|
||||
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
|
||||
@@ -377,7 +377,7 @@ object FirErrors {
|
||||
val INCOMPATIBLE_TYPES_WARNING by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val TYPE_VARIANCE_CONFLICT by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val SMARTCAST_IMPOSSIBLE by error3<KtExpression, ConeKotlinType, FirExpression, String>()
|
||||
val SMARTCAST_IMPOSSIBLE by error4<KtExpression, ConeKotlinType, FirExpression, String, Boolean>()
|
||||
|
||||
// Reflection
|
||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<KtExpression, FirCallableSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -482,7 +482,7 @@ object FirErrors {
|
||||
val CONST_VAL_WITHOUT_INITIALIZER by error0<KtProperty>(SourceElementPositioningStrategies.CONST_MODIFIER)
|
||||
val CONST_VAL_WITH_NON_CONST_INITIALIZER by error0<KtExpression>()
|
||||
val WRONG_SETTER_PARAMETER_TYPE by error2<KtTypeReference, ConeKotlinType, ConeKotlinType>()
|
||||
val INITIALIZER_TYPE_MISMATCH by error2<KtProperty, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.PROPERTY_INITIALIZER)
|
||||
val INITIALIZER_TYPE_MISMATCH by error3<KtProperty, ConeKotlinType, ConeKotlinType, Boolean>(SourceElementPositioningStrategies.PROPERTY_INITIALIZER)
|
||||
val GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
||||
val SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
||||
val WRONG_SETTER_RETURN_TYPE by error0<KtTypeReference>()
|
||||
|
||||
@@ -576,7 +576,14 @@ fun checkTypeMismatch(
|
||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
}
|
||||
isInitializer -> {
|
||||
reporter.reportOn(source, FirErrors.INITIALIZER_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.INITIALIZER_TYPE_MISMATCH,
|
||||
lValueType,
|
||||
rValueType,
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(rValueType, lValueType),
|
||||
context
|
||||
)
|
||||
}
|
||||
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement -> {
|
||||
if (!lValueType.isNullable && rValueType.isNullable) {
|
||||
@@ -591,7 +598,14 @@ fun checkTypeMismatch(
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
reporter.reportOn(source, FirErrors.ASSIGNMENT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.ASSIGNMENT_TYPE_MISMATCH,
|
||||
lValueType,
|
||||
rValueType,
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(rValueType, lValueType),
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -603,7 +617,13 @@ internal fun checkCondition(condition: FirExpression, context: CheckerContext, r
|
||||
coneType !is ConeKotlinErrorType &&
|
||||
!coneType.isSubtypeOf(context.session.typeContext, context.session.builtinTypes.booleanType.type)
|
||||
) {
|
||||
reporter.reportOn(condition.source, FirErrors.CONDITION_TYPE_MISMATCH, coneType, context)
|
||||
reporter.reportOn(
|
||||
condition.source,
|
||||
FirErrors.CONDITION_TYPE_MISMATCH,
|
||||
coneType,
|
||||
coneType.isNullableBoolean,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirTryExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.isTypeMismatchDueToNullability
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
@@ -42,7 +44,16 @@ object FirCatchParameterChecker : FirTryExpressionChecker() {
|
||||
|
||||
val session = context.session
|
||||
if (!coneType.isSubtypeOfThrowable(session)) {
|
||||
reporter.reportOn(source, FirErrors.THROWABLE_TYPE_MISMATCH, coneType, context)
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.THROWABLE_TYPE_MISMATCH,
|
||||
coneType,
|
||||
context.session.inferenceComponents.ctx.isTypeMismatchDueToNullability(
|
||||
coneType,
|
||||
session.builtinTypes.throwableType.type
|
||||
),
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -17,9 +17,9 @@ import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.isExhaustive
|
||||
import org.jetbrains.kotlin.fir.resolve.isTypeMismatchDueToNullability
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.SmartcastStability
|
||||
|
||||
object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||
override fun check(expression: FirReturnExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -38,7 +38,9 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||
if (resultExpression.isNullLiteral && functionReturnType.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(resultExpression.source, NULL_FOR_NONNULL_TYPE, context)
|
||||
} else {
|
||||
if (resultExpression is FirExpressionWithSmartcast && resultExpression.smartcastStability != SmartcastStability.STABLE_VALUE &&
|
||||
val isDueToNullability =
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(returnExpressionType, functionReturnType)
|
||||
if (resultExpression is FirExpressionWithSmartcast && !resultExpression.isStable &&
|
||||
isSubtypeForTypeMismatch(typeContext, subtype = resultExpression.smartcastType.coneType, supertype = functionReturnType)
|
||||
) {
|
||||
reporter.reportOn(
|
||||
@@ -47,6 +49,7 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||
functionReturnType,
|
||||
resultExpression,
|
||||
resultExpression.smartcastStability.description,
|
||||
isDueToNullability,
|
||||
context
|
||||
)
|
||||
} else {
|
||||
@@ -56,6 +59,7 @@ object FirFunctionReturnTypeMismatchChecker : FirReturnExpressionChecker() {
|
||||
functionReturnType,
|
||||
returnExpressionType,
|
||||
targetElement,
|
||||
isDueToNullability,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
+9
-8
@@ -812,9 +812,9 @@ class FirDefaultErrorMessages {
|
||||
map.put(REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_ANNOTATION, "Redundant spread (*) operator");
|
||||
map.put(REDUNDANT_SPREAD_OPERATOR_IN_NAMED_FORM_IN_FUNCTION, "Redundant spread (*) operator");
|
||||
|
||||
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(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING, NOT_RENDERED)
|
||||
map.put(THROWABLE_TYPE_MISMATCH, "Throwable type mismatch: actual type is {0}", TO_STRING, NOT_RENDERED)
|
||||
map.put(CONDITION_TYPE_MISMATCH, "Condition type mismatch: inferred type is {0} but Boolean was expected", TO_STRING, NOT_RENDERED)
|
||||
map.put(
|
||||
ARGUMENT_TYPE_MISMATCH,
|
||||
"Argument type mismatch: actual type is {1} but {0} was expected",
|
||||
@@ -822,12 +822,12 @@ class FirDefaultErrorMessages {
|
||||
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, NOT_RENDERED)
|
||||
map.put(
|
||||
RESULT_TYPE_MISMATCH,
|
||||
"Function return type mismatch: actual type is {1} but {0} was expected",
|
||||
RENDER_TYPE,
|
||||
RENDER_TYPE
|
||||
RENDER_TYPE,
|
||||
)
|
||||
|
||||
// Ambiguity
|
||||
@@ -921,7 +921,8 @@ class FirDefaultErrorMessages {
|
||||
"Smart cast to ''{0}'' is impossible, because ''{1}'' is a {2}",
|
||||
RENDER_TYPE,
|
||||
FIR,
|
||||
TO_STRING
|
||||
TO_STRING,
|
||||
NOT_RENDERED
|
||||
)
|
||||
|
||||
map.put(
|
||||
@@ -966,7 +967,7 @@ class FirDefaultErrorMessages {
|
||||
|
||||
map.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')")
|
||||
|
||||
map.put(RETURN_TYPE_MISMATCH, "Return type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE, NOT_RENDERED)
|
||||
map.put(RETURN_TYPE_MISMATCH, "Return type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE, NOT_RENDERED, NOT_RENDERED)
|
||||
|
||||
map.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds")
|
||||
|
||||
@@ -1279,7 +1280,7 @@ class FirDefaultErrorMessages {
|
||||
RENDER_TYPE,
|
||||
RENDER_TYPE
|
||||
)
|
||||
map.put(INITIALIZER_TYPE_MISMATCH, "Initializer type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE)
|
||||
map.put(INITIALIZER_TYPE_MISMATCH, "Initializer type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE, NOT_RENDERED)
|
||||
map.put(GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, "Getter visibility must be the same as property visibility")
|
||||
map.put(
|
||||
SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY,
|
||||
|
||||
+24
-4
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeVariableForLambdaRetur
|
||||
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.ConeLambdaArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.isTypeMismatchDueToNullability
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
@@ -60,7 +61,8 @@ private fun ConeDiagnostic.toFirDiagnostic(
|
||||
unstableSmartcast.argument.source,
|
||||
unstableSmartcast.targetType,
|
||||
unstableSmartcast.argument,
|
||||
unstableSmartcast.argument.smartcastStability.description
|
||||
unstableSmartcast.argument.smartcastStability.description,
|
||||
unstableSmartcast.isCastToNotNull
|
||||
)
|
||||
}
|
||||
else -> FirErrors.NONE_APPLICABLE.createOn(source, this.candidates.map { it.symbol })
|
||||
@@ -203,7 +205,8 @@ private fun mapInapplicableCandidateError(
|
||||
rootCause.argument.source,
|
||||
rootCause.targetType,
|
||||
rootCause.argument,
|
||||
rootCause.argument.smartcastStability.description
|
||||
rootCause.argument.smartcastStability.description,
|
||||
rootCause.isCastToNotNull
|
||||
)
|
||||
else -> genericDiagnostic
|
||||
}
|
||||
@@ -278,12 +281,13 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
else -> null
|
||||
}
|
||||
|
||||
val typeMismatchDueToNullability = typeContext.isTypeMismatchDueToNullability(lowerConeType, upperConeType)
|
||||
argument?.let {
|
||||
return FirErrors.ARGUMENT_TYPE_MISMATCH.createOn(
|
||||
it.source ?: source,
|
||||
lowerConeType,
|
||||
upperConeType,
|
||||
isArgumentTypeMismatchDueToNullability(lowerConeType, upperConeType, typeContext)
|
||||
typeMismatchDueToNullability
|
||||
)
|
||||
}
|
||||
|
||||
@@ -299,7 +303,12 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
else
|
||||
upperConeType.withNullability(ConeNullability.NULLABLE, typeContext)
|
||||
|
||||
FirErrors.TYPE_MISMATCH.createOn(qualifiedAccessSource ?: source, upperConeType, inferredType)
|
||||
FirErrors.TYPE_MISMATCH.createOn(
|
||||
qualifiedAccessSource ?: source,
|
||||
upperConeType,
|
||||
inferredType,
|
||||
typeMismatchDueToNullability
|
||||
)
|
||||
}
|
||||
is ExplicitTypeParameterConstraintPosition<*>,
|
||||
is DelegatedPropertyConstraintPosition<*> -> {
|
||||
@@ -418,3 +427,14 @@ private fun <A, B, C> FirDiagnosticFactory3<A, B, C>.createOn(
|
||||
): FirDiagnosticWithParameters3<A, B, C>? {
|
||||
return element?.let { on(it, a, b, c, positioningStrategy = null) }
|
||||
}
|
||||
|
||||
@OptIn(InternalDiagnosticFactoryMethod::class)
|
||||
private fun <A, B, C, D> FirDiagnosticFactory4<A, B, C, D>.createOn(
|
||||
element: FirSourceElement?,
|
||||
a: A,
|
||||
b: B,
|
||||
c: C,
|
||||
d: D
|
||||
): FirDiagnosticWithParameters4<A, B, C, D>? {
|
||||
return element?.let { on(it, a, b, c, d, positioningStrategy = null) }
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ val ConeKotlinType.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Not
|
||||
val ConeKotlinType.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
||||
val ConeKotlinType.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||
val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||
val ConeKotlinType.isNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, true)
|
||||
val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Boolean))
|
||||
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.SmartcastStability
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -549,3 +550,15 @@ fun FirClassLikeDeclaration.getContainingDeclaration(session: FirSession): FirCl
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun ConeTypeContext.isTypeMismatchDueToNullability(
|
||||
actualType: ConeKotlinType,
|
||||
expectedType: ConeKotlinType
|
||||
): Boolean {
|
||||
return actualType.isNullableType() && !expectedType.isNullableType() && AbstractTypeChecker.isSubtypeOf(
|
||||
this,
|
||||
actualType,
|
||||
expectedType.withNullability(ConeNullability.NULLABLE, this)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.*
|
||||
import org.jetbrains.kotlin.fir.resolve.isTypeMismatchDueToNullability
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
||||
import org.jetbrains.kotlin.fir.returnExpressions
|
||||
@@ -340,18 +341,6 @@ private fun Candidate.captureTypeFromExpressionOrNull(argumentType: ConeKotlinTy
|
||||
) as? ConeKotlinType
|
||||
}
|
||||
|
||||
fun isArgumentTypeMismatchDueToNullability(
|
||||
argumentType: ConeKotlinType,
|
||||
actualExpectedType: ConeKotlinType,
|
||||
typeContext: ConeTypeContext
|
||||
): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(
|
||||
typeContext,
|
||||
argumentType,
|
||||
actualExpectedType.withNullability(ConeNullability.NULLABLE, typeContext)
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkApplicabilityForArgumentType(
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: FirExpression,
|
||||
@@ -394,7 +383,7 @@ private fun checkApplicabilityForArgumentType(
|
||||
argument,
|
||||
// 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.
|
||||
isArgumentTypeMismatchDueToNullability(argumentType, actualExpectedType, context.session.typeContext)
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(argumentType, actualExpectedType)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -410,7 +399,16 @@ private fun checkApplicabilityForArgumentType(
|
||||
if (smartcastExpression != null && !smartcastExpression.isStable) {
|
||||
val unstableType = smartcastExpression.smartcastType.coneType
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
|
||||
sink.reportDiagnostic(UnstableSmartCast(smartcastExpression, expectedType))
|
||||
sink.reportDiagnostic(
|
||||
UnstableSmartCast(
|
||||
smartcastExpression,
|
||||
expectedType,
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(
|
||||
argumentType,
|
||||
expectedType
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ object LowerPriorityToPreserveCompatibilityDiagnostic : ResolutionDiagnostic(RES
|
||||
|
||||
object CandidateChosenUsingOverloadResolutionByLambdaAnnotation : ResolutionDiagnostic(RESOLVED)
|
||||
|
||||
class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType) : ResolutionDiagnostic(UNSTABLE_SMARTCAST)
|
||||
class UnstableSmartCast(val argument: FirExpressionWithSmartcast, val targetType: ConeKotlinType, val isCastToNotNull: Boolean) : ResolutionDiagnostic(UNSTABLE_SMARTCAST)
|
||||
|
||||
class ArgumentTypeMismatch(
|
||||
val expectedType: ConeKotlinType,
|
||||
|
||||
+11
-1
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.*
|
||||
import org.jetbrains.kotlin.fir.resolve.isTypeMismatchDueToNullability
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FirUnstableSmartcastTypeScope
|
||||
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
|
||||
@@ -121,7 +122,16 @@ object CheckDispatchReceiver : ResolutionStage() {
|
||||
!explicitReceiverExpression.isStable &&
|
||||
(isCandidateFromUnstableSmartcast || (isReceiverNullable && !explicitReceiverExpression.smartcastType.canBeNull))
|
||||
) {
|
||||
sink.yieldDiagnostic(UnstableSmartCast(explicitReceiverExpression, explicitReceiverExpression.smartcastType.coneType))
|
||||
sink.yieldDiagnostic(
|
||||
UnstableSmartCast(
|
||||
explicitReceiverExpression,
|
||||
explicitReceiverExpression.smartcastType.coneType,
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(
|
||||
explicitReceiverExpression.originalType.coneType,
|
||||
explicitReceiverExpression.smartcastType.coneType
|
||||
)
|
||||
)
|
||||
)
|
||||
} else if (isReceiverNullable) {
|
||||
sink.yieldDiagnostic(UnsafeCall(dispatchReceiverValueType))
|
||||
}
|
||||
|
||||
+6
-2
@@ -9,9 +9,13 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ArgumentTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.CheckerSink
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
|
||||
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.isTypeMismatchDueToNullability
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
@@ -63,7 +67,7 @@ fun Candidate.preprocessLambdaArgument(
|
||||
lambdaType,
|
||||
expectedType,
|
||||
argument,
|
||||
isArgumentTypeMismatchDueToNullability(lambdaType, expectedType, context.session.typeContext)
|
||||
context.session.typeContext.isTypeMismatchDueToNullability(lambdaType, expectedType)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user