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> {
|
val CAPTURED_MEMBER_VAL_INITIALIZATION by error<KtExpression> {
|
||||||
parameter<FirPropertySymbol>("property")
|
parameter<FirPropertySymbol>("property")
|
||||||
}
|
}
|
||||||
|
val SETTER_PROJECTED_OUT by error<KtBinaryExpression>(PositioningStrategy.ASSIGNMENT_LHS) {
|
||||||
|
parameter<FirPropertySymbol>("property")
|
||||||
|
}
|
||||||
val WRONG_INVOCATION_KIND by warning<PsiElement> {
|
val WRONG_INVOCATION_KIND by warning<PsiElement> {
|
||||||
parameter<Symbol>("declaration")
|
parameter<Symbol>("declaration")
|
||||||
parameter<EventOccurrencesRange>("requiredRange")
|
parameter<EventOccurrencesRange>("requiredRange")
|
||||||
|
|||||||
@@ -451,6 +451,7 @@ object FirErrors {
|
|||||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR by error1<KtExpression, FirPropertySymbol>()
|
val VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR by error1<KtExpression, FirPropertySymbol>()
|
||||||
val CAPTURED_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
val CAPTURED_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||||
val CAPTURED_MEMBER_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 WRONG_INVOCATION_KIND by warning3<PsiElement, FirBasedSymbol<*>, EventOccurrencesRange, EventOccurrencesRange>()
|
||||||
val LEAKED_IN_PLACE_LAMBDA by error1<PsiElement, FirBasedSymbol<*>>()
|
val LEAKED_IN_PLACE_LAMBDA by error1<PsiElement, FirBasedSymbol<*>>()
|
||||||
val WRONG_IMPLIES_CONDITION by warning0<PsiElement>()
|
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.analysis.getChild
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||||
@@ -535,6 +533,7 @@ val ConeTypeProjection.isConflictingOrNotInvariant: Boolean get() = kind != Proj
|
|||||||
|
|
||||||
fun checkTypeMismatch(
|
fun checkTypeMismatch(
|
||||||
lValueOriginalType: ConeKotlinType,
|
lValueOriginalType: ConeKotlinType,
|
||||||
|
assignment: FirVariableAssignment?,
|
||||||
rValue: FirExpression,
|
rValue: FirExpression,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
source: FirSourceElement,
|
source: FirSourceElement,
|
||||||
@@ -543,25 +542,16 @@ fun checkTypeMismatch(
|
|||||||
) {
|
) {
|
||||||
var lValueType = lValueOriginalType
|
var lValueType = lValueOriginalType
|
||||||
var rValueType = rValue.typeRef.coneType
|
var rValueType = rValue.typeRef.coneType
|
||||||
val typeContext = context.session.typeContext
|
if (source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement) {
|
||||||
|
if (!lValueType.isNullable && rValueType.isNullable) {
|
||||||
val diagnosticFactory = when {
|
val tempType = rValueType
|
||||||
isInitializer -> {
|
rValueType = lValueType
|
||||||
FirErrors.INITIALIZER_TYPE_MISMATCH
|
lValueType = tempType
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val typeContext = context.session.typeContext
|
||||||
|
|
||||||
if (!isSubtypeForTypeMismatch(typeContext, subtype = rValueType, supertype = lValueType)) {
|
if (!isSubtypeForTypeMismatch(typeContext, subtype = rValueType, supertype = lValueType)) {
|
||||||
if (rValueType is ConeClassLikeType &&
|
if (rValueType is ConeClassLikeType &&
|
||||||
rValueType.lookupTag.classId == StandardClassIds.Int &&
|
rValueType.lookupTag.classId == StandardClassIds.Int &&
|
||||||
@@ -576,10 +566,30 @@ fun checkTypeMismatch(
|
|||||||
// TODO: remove after fix of KT-45989
|
// TODO: remove after fix of KT-45989
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (rValue.isNullLiteral && lValueType.nullability == ConeNullability.NOT_NULL) {
|
val resolvedSymbol = assignment?.calleeReference?.toResolvedCallableSymbol() as? FirPropertySymbol
|
||||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
when {
|
||||||
} else {
|
resolvedSymbol != null && lValueType is ConeCapturedType && lValueType.constructor.projection.kind.let {
|
||||||
reporter.reportOn(source, diagnosticFactory, lValueType, rValueType, context)
|
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
|
if (declaration.returnTypeRef.source?.kind != FirRealSourceElementKind) return
|
||||||
val propertyType = declaration.returnTypeRef.coneType
|
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.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
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
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
|
||||||
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
||||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val source = expression.rValue.source ?: return
|
val source = expression.rValue.source ?: return
|
||||||
val coneType = expression.lValueTypeRef.coneType
|
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
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SEALED_SUPERTYPE_IN_LOCAL_CLASS
|
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.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.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.SINGLETON_IN_SUPERTYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SMARTCAST_IMPOSSIBLE
|
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",
|
"Captured member values initialization is forbidden due to possible reassignment",
|
||||||
VARIABLE_NAME
|
VARIABLE_NAME
|
||||||
)
|
)
|
||||||
|
map.put(
|
||||||
|
SETTER_PROJECTED_OUT,
|
||||||
|
"Setter for ''{0}'' is removed by type projection",
|
||||||
|
VARIABLE_NAME
|
||||||
|
)
|
||||||
map.put(
|
map.put(
|
||||||
WRONG_INVOCATION_KIND,
|
WRONG_INVOCATION_KIND,
|
||||||
"{2} wrong invocation kind: given {3} case, but {4} case is possible",
|
"{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
|
// !DIAGNOSTICS: -UNREACHABLE_CODE -UNUSED_PARAMETER
|
||||||
// !CHECK_TYPE
|
// !CHECK_TYPE
|
||||||
// t is unused due to KT-4233
|
// 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
|
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
||||||
interface Tr<T> {
|
interface Tr<T> {
|
||||||
var v: T
|
var v: T
|
||||||
|
|||||||
+7
@@ -2250,6 +2250,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.SETTER_PROJECTED_OUT) { firDiagnostic ->
|
||||||
|
SetterProjectedOutImpl(
|
||||||
|
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.WRONG_INVOCATION_KIND) { firDiagnostic ->
|
add(FirErrors.WRONG_INVOCATION_KIND) { firDiagnostic ->
|
||||||
WrongInvocationKindImpl(
|
WrongInvocationKindImpl(
|
||||||
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration),
|
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration),
|
||||||
|
|||||||
+5
@@ -1585,6 +1585,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val property: KtVariableSymbol
|
abstract val property: KtVariableSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class SetterProjectedOut : KtFirDiagnostic<KtBinaryExpression>() {
|
||||||
|
override val diagnosticClass get() = SetterProjectedOut::class
|
||||||
|
abstract val property: KtVariableSymbol
|
||||||
|
}
|
||||||
|
|
||||||
abstract class WrongInvocationKind : KtFirDiagnostic<PsiElement>() {
|
abstract class WrongInvocationKind : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = WrongInvocationKind::class
|
override val diagnosticClass get() = WrongInvocationKind::class
|
||||||
abstract val declaration: KtSymbol
|
abstract val declaration: KtSymbol
|
||||||
|
|||||||
+8
@@ -2564,6 +2564,14 @@ internal class CapturedMemberValInitializationImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
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(
|
internal class WrongInvocationKindImpl(
|
||||||
override val declaration: KtSymbol,
|
override val declaration: KtSymbol,
|
||||||
override val requiredRange: EventOccurrencesRange,
|
override val requiredRange: EventOccurrencesRange,
|
||||||
|
|||||||
Reference in New Issue
Block a user