FIR checker: report SETTER_PROJECTED_OUT

This commit is contained in:
Tianyu Geng
2021-06-17 21:36:07 +03:00
committed by TeamCityServer
parent c3a91efea3
commit cdfb2fb3d9
13 changed files with 77 additions and 48 deletions
@@ -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>()
@@ -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)
}
}
}
}
@@ -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)
}
}
@@ -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,
)
}
}
@@ -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",
@@ -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,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNREACHABLE_CODE -UNUSED_PARAMETER
// !CHECK_TYPE
// t is unused due to KT-4233
@@ -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!!<!>
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNREACHABLE_CODE
interface Tr<T> {
var v: T
@@ -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),
@@ -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
@@ -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,