FIR checker: report SETTER_PROJECTED_OUT
This commit is contained in:
committed by
TeamCityServer
parent
c3a91efea3
commit
cdfb2fb3d9
+3
@@ -811,6 +811,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val CAPTURED_MEMBER_VAL_INITIALIZATION by error<KtExpression> {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
}
|
||||
val SETTER_PROJECTED_OUT by error<KtBinaryExpression>(PositioningStrategy.ASSIGNMENT_LHS) {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
}
|
||||
val WRONG_INVOCATION_KIND by warning<PsiElement> {
|
||||
parameter<Symbol>("declaration")
|
||||
parameter<EventOccurrencesRange>("requiredRange")
|
||||
|
||||
@@ -451,6 +451,7 @@ object FirErrors {
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR by error1<KtExpression, FirPropertySymbol>()
|
||||
val CAPTURED_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||
val CAPTURED_MEMBER_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||
val SETTER_PROJECTED_OUT by error1<KtBinaryExpression, FirPropertySymbol>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
val WRONG_INVOCATION_KIND by warning3<PsiElement, FirBasedSymbol<*>, EventOccurrencesRange, EventOccurrencesRange>()
|
||||
val LEAKED_IN_PLACE_LAMBDA by error1<PsiElement, FirBasedSymbol<*>>()
|
||||
val WRONG_IMPLIES_CONDITION by warning0<PsiElement>()
|
||||
|
||||
+33
-23
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||
@@ -535,6 +533,7 @@ val ConeTypeProjection.isConflictingOrNotInvariant: Boolean get() = kind != Proj
|
||||
|
||||
fun checkTypeMismatch(
|
||||
lValueOriginalType: ConeKotlinType,
|
||||
assignment: FirVariableAssignment?,
|
||||
rValue: FirExpression,
|
||||
context: CheckerContext,
|
||||
source: FirSourceElement,
|
||||
@@ -543,25 +542,16 @@ fun checkTypeMismatch(
|
||||
) {
|
||||
var lValueType = lValueOriginalType
|
||||
var rValueType = rValue.typeRef.coneType
|
||||
val typeContext = context.session.typeContext
|
||||
|
||||
val diagnosticFactory = when {
|
||||
isInitializer -> {
|
||||
FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
}
|
||||
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement -> {
|
||||
if (!lValueType.isNullable && rValueType.isNullable) {
|
||||
val tempType = rValueType
|
||||
rValueType = lValueType
|
||||
lValueType = tempType
|
||||
}
|
||||
FirErrors.RESULT_TYPE_MISMATCH
|
||||
}
|
||||
else -> {
|
||||
FirErrors.ASSIGNMENT_TYPE_MISMATCH
|
||||
if (source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement) {
|
||||
if (!lValueType.isNullable && rValueType.isNullable) {
|
||||
val tempType = rValueType
|
||||
rValueType = lValueType
|
||||
lValueType = tempType
|
||||
}
|
||||
}
|
||||
|
||||
val typeContext = context.session.typeContext
|
||||
|
||||
if (!isSubtypeForTypeMismatch(typeContext, subtype = rValueType, supertype = lValueType)) {
|
||||
if (rValueType is ConeClassLikeType &&
|
||||
rValueType.lookupTag.classId == StandardClassIds.Int &&
|
||||
@@ -576,10 +566,30 @@ fun checkTypeMismatch(
|
||||
// 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 {
|
||||
reporter.reportOn(source, diagnosticFactory, lValueType, rValueType, context)
|
||||
val resolvedSymbol = assignment?.calleeReference?.toResolvedCallableSymbol() as? FirPropertySymbol
|
||||
when {
|
||||
resolvedSymbol != null && lValueType is ConeCapturedType && lValueType.constructor.projection.kind.let {
|
||||
it == ProjectionKind.STAR || it == ProjectionKind.OUT
|
||||
} -> {
|
||||
reporter.reportOn(assignment.source, FirErrors.SETTER_PROJECTED_OUT, resolvedSymbol, context)
|
||||
}
|
||||
rValue.isNullLiteral && lValueType.nullability == ConeNullability.NOT_NULL -> {
|
||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
}
|
||||
isInitializer -> {
|
||||
reporter.reportOn(source, FirErrors.INITIALIZER_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
}
|
||||
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement -> {
|
||||
if (!lValueType.isNullable && rValueType.isNullable) {
|
||||
val tempType = rValueType
|
||||
rValueType = lValueType
|
||||
lValueType = tempType
|
||||
}
|
||||
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
}
|
||||
else -> {
|
||||
reporter.reportOn(source, FirErrors.ASSIGNMENT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,6 +23,6 @@ object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
||||
if (declaration.returnTypeRef.source?.kind != FirRealSourceElementKind) return
|
||||
val propertyType = declaration.returnTypeRef.coneType
|
||||
|
||||
checkTypeMismatch(propertyType, initializer, context, source, reporter, true)
|
||||
checkTypeMismatch(propertyType, null, initializer, context, source, reporter, true)
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -9,12 +9,22 @@ 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.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = expression.rValue.source ?: return
|
||||
val coneType = expression.lValueTypeRef.coneType
|
||||
checkTypeMismatch(coneType, expression.rValue, context, source, reporter, false)
|
||||
checkTypeMismatch(
|
||||
coneType,
|
||||
expression,
|
||||
expression.rValue,
|
||||
context,
|
||||
source,
|
||||
reporter,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -301,6 +301,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_CLASS_CONS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_PROJECTED_OUT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SINGLETON_IN_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE
|
||||
@@ -1096,6 +1097,11 @@ class FirDefaultErrorMessages {
|
||||
"Captured member values initialization is forbidden due to possible reassignment",
|
||||
VARIABLE_NAME
|
||||
)
|
||||
map.put(
|
||||
SETTER_PROJECTED_OUT,
|
||||
"Setter for ''{0}'' is removed by type projection",
|
||||
VARIABLE_NAME
|
||||
)
|
||||
map.put(
|
||||
WRONG_INVOCATION_KIND,
|
||||
"{2} wrong invocation kind: given {3} case, but {4} case is possible",
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNREACHABLE_CODE -UNUSED_PARAMETER
|
||||
// !CHECK_TYPE
|
||||
// t is unused due to KT-4233
|
||||
interface Tr<T> {
|
||||
var v: T
|
||||
}
|
||||
|
||||
fun test(t: Tr<*>) {
|
||||
t.v = null!!
|
||||
t.v = <!ASSIGNMENT_TYPE_MISMATCH!>""<!>
|
||||
t.v = <!NULL_FOR_NONNULL_TYPE!>null<!>
|
||||
t.v checkType { _<Any?>() }
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNREACHABLE_CODE -UNUSED_PARAMETER
|
||||
// !CHECK_TYPE
|
||||
// t is unused due to KT-4233
|
||||
|
||||
Vendored
-10
@@ -1,10 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
||||
interface Tr<T> {
|
||||
var v: T
|
||||
}
|
||||
|
||||
fun test(t: Tr<out String>) {
|
||||
// resolved as t.v = t.v + null!!, where type of right operand is String,
|
||||
// so TYPE_MISMATCH: String is not <: of Captured(out String)
|
||||
<!ASSIGNMENT_TYPE_MISMATCH!>t.v += null!!<!>
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
||||
interface Tr<T> {
|
||||
var v: T
|
||||
|
||||
+7
@@ -2250,6 +2250,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.SETTER_PROJECTED_OUT) { firDiagnostic ->
|
||||
SetterProjectedOutImpl(
|
||||
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.WRONG_INVOCATION_KIND) { firDiagnostic ->
|
||||
WrongInvocationKindImpl(
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration),
|
||||
|
||||
+5
@@ -1585,6 +1585,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val property: KtVariableSymbol
|
||||
}
|
||||
|
||||
abstract class SetterProjectedOut : KtFirDiagnostic<KtBinaryExpression>() {
|
||||
override val diagnosticClass get() = SetterProjectedOut::class
|
||||
abstract val property: KtVariableSymbol
|
||||
}
|
||||
|
||||
abstract class WrongInvocationKind : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = WrongInvocationKind::class
|
||||
abstract val declaration: KtSymbol
|
||||
|
||||
+8
@@ -2564,6 +2564,14 @@ internal class CapturedMemberValInitializationImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class SetterProjectedOutImpl(
|
||||
override val property: KtVariableSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.SetterProjectedOut(), KtAbstractFirDiagnostic<KtBinaryExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class WrongInvocationKindImpl(
|
||||
override val declaration: KtSymbol,
|
||||
override val requiredRange: EventOccurrencesRange,
|
||||
|
||||
Reference in New Issue
Block a user