[FIR] Implement ASSIGNMENT_TYPE_MISMATCH, RESULT_TYPE_MISMATCH diagnostics, fix tests
This commit is contained in:
committed by
TeamCityServer
parent
aa70c952eb
commit
e57108d4e8
+1
-1
@@ -107,7 +107,7 @@ fun foo() {
|
||||
if (bool) <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 4 else <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 42
|
||||
val <!VARIABLE_NEVER_READ!>b<!>: String
|
||||
|
||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>b<!> = false
|
||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>b<!> = <!ASSIGNMENT_TYPE_MISMATCH!>false<!>
|
||||
}
|
||||
|
||||
fun cycles() {
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@ fun foo() {
|
||||
// now, Idea hightlights this code like error (cuz listVar
|
||||
// is mutable and listVar + 4 is immutable) and like warning
|
||||
// (cuz can be replaced with +=)
|
||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>listVar<!> = listVar + 4
|
||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>listVar<!> = <!ASSIGNMENT_TYPE_MISMATCH!>listVar + 4<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ class B(p0: String) {
|
||||
p3 = p1
|
||||
}
|
||||
init {
|
||||
p1 = p0.length
|
||||
p1 = <!ASSIGNMENT_TYPE_MISMATCH!>p0.length<!>
|
||||
p3 = ""
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -272,6 +272,16 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<String>("name")
|
||||
}
|
||||
|
||||
val ASSIGNMENT_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expected")
|
||||
parameter<ConeKotlinType>("actual")
|
||||
}
|
||||
|
||||
val RESULT_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expected")
|
||||
parameter<ConeKotlinType>("actual")
|
||||
}
|
||||
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
|
||||
}
|
||||
|
||||
|
||||
@@ -226,6 +226,8 @@ object FirErrors {
|
||||
val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableDeclaration<*>>()
|
||||
val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameter>(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 RESULT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
||||
|
||||
// Ambiguity
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
|
||||
@@ -33,8 +34,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
|
||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
||||
@@ -519,3 +519,45 @@ private val FirSimpleFunction.matchesHashCodeSignature: Boolean
|
||||
|
||||
private val FirSimpleFunction.matchesToStringSignature: Boolean
|
||||
get() = valueParameters.isEmpty()
|
||||
|
||||
fun checkTypeMismatch(
|
||||
lValueType: ConeKotlinType,
|
||||
rValue: FirExpression,
|
||||
context: CheckerContext,
|
||||
source: FirSourceElement,
|
||||
reporter: DiagnosticReporter,
|
||||
isInitializer: Boolean
|
||||
) {
|
||||
val rValueType = rValue.typeRef.coneType
|
||||
val typeContext = context.session.typeContext
|
||||
|
||||
if (!isSubtypeForTypeMismatch(typeContext, subtype = rValueType, supertype = lValueType)) {
|
||||
if (rValueType is ConeClassLikeType &&
|
||||
rValueType.lookupTag.classId == StandardClassIds.Int &&
|
||||
lValueType.fullyExpandedType(context.session).isIntegerTypeOrNullableIntegerTypeOfAnySize &&
|
||||
rValueType.nullability == ConeNullability.NOT_NULL
|
||||
) {
|
||||
// val p: Byte = 42 or similar situation
|
||||
// TODO: remove after fix of KT-46047
|
||||
return
|
||||
}
|
||||
if (lValueType.isExtensionFunctionType || rValueType.isExtensionFunctionType) {
|
||||
// TODO: remove after fix of KT-45989
|
||||
return
|
||||
}
|
||||
if (rValue.isNullLiteral && lValueType.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
} else {
|
||||
val diagnosticFactory = when {
|
||||
isInitializer ->
|
||||
FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement ->
|
||||
FirErrors.RESULT_TYPE_MISMATCH
|
||||
else ->
|
||||
FirErrors.ASSIGNMENT_TYPE_MISMATCH
|
||||
}
|
||||
|
||||
reporter.report(diagnosticFactory.on(source, lValueType, rValueType), context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-31
@@ -7,18 +7,12 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isComponentCall
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -28,28 +22,7 @@ object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
||||
if (initializer is FirComponentCall) return
|
||||
if (declaration.returnTypeRef.source?.kind != FirRealSourceElementKind) return
|
||||
val propertyType = declaration.returnTypeRef.coneType
|
||||
val expressionType = initializer.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||
val typeContext = context.session.typeContext
|
||||
|
||||
if (!isSubtypeForTypeMismatch(typeContext, subtype = expressionType, supertype = propertyType)) {
|
||||
if (expressionType is ConeClassLikeType &&
|
||||
expressionType.lookupTag.classId == StandardClassIds.Int &&
|
||||
propertyType.fullyExpandedType(context.session).isIntegerTypeOrNullableIntegerTypeOfAnySize &&
|
||||
expressionType.nullability == ConeNullability.NOT_NULL
|
||||
) {
|
||||
// val p: Byte = 42 or similar situation
|
||||
// TODO: remove after fix of KT-46047
|
||||
return
|
||||
}
|
||||
if (propertyType.isExtensionFunctionType || expressionType.isExtensionFunctionType) {
|
||||
// TODO: remove after fix of KT-45989
|
||||
return
|
||||
}
|
||||
if (initializer.isNullLiteral && propertyType.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(initializer.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
} else {
|
||||
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
|
||||
}
|
||||
}
|
||||
checkTypeMismatch(propertyType, initializer, context, source, reporter, true)
|
||||
}
|
||||
}
|
||||
+7
-11
@@ -5,25 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
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.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isNullLiteral
|
||||
|
||||
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val rValue = expression.rValue
|
||||
if (rValue.isNullLiteral) {
|
||||
val leftType = ((expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol)?.fir?.returnTypeRef
|
||||
if (leftType?.coneType?.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
}
|
||||
}
|
||||
val source = expression.rValue.source ?: return
|
||||
val lValueType =
|
||||
((expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol)?.fir?.returnTypeRef?.coneType
|
||||
?: return
|
||||
|
||||
checkTypeMismatch(lValueType, expression.rValue, context, source, reporter, false)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user