[FIR] Allow lateinit FirBackingField's

This commit is contained in:
Nikolay Lunyak
2021-09-08 11:47:45 +03:00
committed by TeamCityServer
parent 871aebd423
commit 6b532ccd0d
11 changed files with 119 additions and 39 deletions
@@ -875,6 +875,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val ACCESSOR_FOR_DELEGATED_PROPERTY by error<KtPropertyAccessor>()
val PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION by error<KtExpression>()
val PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER by error<KtBackingField>()
val LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER by error<KtBackingField>(PositioningStrategy.LATEINIT_MODIFIER)
val LATEINIT_FIELD_IN_VAL_PROPERTY by error<KtBackingField>(PositioningStrategy.LATEINIT_MODIFIER)
val LATEINIT_NULLABLE_BACKING_FIELD by error<KtBackingField>(PositioningStrategy.LATEINIT_MODIFIER)
val PROPERTY_MUST_HAVE_GETTER by error<KtProperty>()
val PROPERTY_MUST_HAVE_SETTER by error<KtProperty>()
val EXPLICIT_BACKING_FIELD_IN_INTERFACE by error<KtBackingField>(PositioningStrategy.FIELD_KEYWORD)
@@ -482,6 +482,9 @@ object FirErrors {
val ACCESSOR_FOR_DELEGATED_PROPERTY by error0<KtPropertyAccessor>()
val PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION by error0<KtExpression>()
val PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER by error0<KtBackingField>()
val LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER by error0<KtBackingField>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
val LATEINIT_FIELD_IN_VAL_PROPERTY by error0<KtBackingField>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
val LATEINIT_NULLABLE_BACKING_FIELD by error0<KtBackingField>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
val PROPERTY_MUST_HAVE_GETTER by error0<KtProperty>()
val PROPERTY_MUST_HAVE_SETTER by error0<KtProperty>()
val EXPLICIT_BACKING_FIELD_IN_INTERFACE by error0<KtBackingField>(SourceElementPositioningStrategies.FIELD_KEYWORD)
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
import org.jetbrains.kotlin.fir.types.*
@@ -44,6 +45,9 @@ object FirInapplicableLateinitChecker : FirPropertyChecker() {
reporter.reportError(declaration.source, "is not allowed on properties of primitive types", context)
}
declaration.hasExplicitBackingField ->
reporter.reportError(declaration.source, "must be moved to the field declaration", context)
declaration.hasGetter() || declaration.hasSetter() ->
reporter.reportError(declaration.source, "is not allowed on properties with a custom getter or setter", context)
}
@@ -9,13 +9,17 @@ 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.declarations.FirBackingField
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isNullable
import org.jetbrains.kotlin.fir.types.isSubtypeOf
object FirPropertyFieldTypeChecker : FirPropertyChecker() {
@@ -35,8 +39,18 @@ object FirPropertyFieldTypeChecker : FirPropertyChecker() {
reporter.reportOn(declaration.initializer?.source, FirErrors.PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION, context)
}
if (backingField.initializer == null) {
if (backingField.isLateInit && declaration.isVal) {
reporter.reportOn(backingField.source, FirErrors.LATEINIT_FIELD_IN_VAL_PROPERTY, context)
}
if (backingField.initializer == null && !backingField.isLateInit) {
reporter.reportOn(backingField.source, FirErrors.PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER, context)
} else if (backingField.initializer != null && backingField.isLateInit) {
reporter.reportOn(backingField.source, FirErrors.LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER, context)
}
if (backingField.isLateInit && backingField.isNullable) {
reporter.reportOn(backingField.source, FirErrors.LATEINIT_NULLABLE_BACKING_FIELD, context)
}
if (backingField.returnTypeRef.coneType == declaration.returnTypeRef.coneType) {
@@ -53,6 +67,12 @@ object FirPropertyFieldTypeChecker : FirPropertyChecker() {
}
}
private val FirBackingField.isNullable
get() = when (val type = returnTypeRef.coneType) {
is ConeTypeParameterType -> type.isNullable || type.lookupTag.typeParameterSymbol.resolvedBounds.any { it.coneType.isNullable }
else -> type.isNullable
}
private val FirPropertyAccessor?.isNotExplicit
get() = this == null || this is FirDefaultPropertyAccessor
@@ -257,6 +257,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_REFEREN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IS_ENUM_ENTRY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_FIELD_IN_VAL_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_NULLABLE_BACKING_FIELD
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_INTERFACE_NOT_ALLOWED
@@ -1283,6 +1286,18 @@ class FirDefaultErrorMessages {
PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER,
"Property backing field declaration must have an initializer"
)
map.put(
LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER,
"Lateinit backing field cannot have an initializer"
)
map.put(
LATEINIT_FIELD_IN_VAL_PROPERTY,
"Only mutable properties can have a mutable backing field. Consider changing ''val'' to ''var''"
)
map.put(
LATEINIT_NULLABLE_BACKING_FIELD,
"Lateinit modifier is not allowed on backing fields of a type with nullable upper bound"
)
map.put(
PROPERTY_MUST_HAVE_GETTER,
"This property needs a custom getter, because it's type is not a supertype of the backing field's type"
@@ -1403,6 +1403,7 @@ class DeclarationsConverter(
return FirDeclarationStatusImpl(componentVisibility, modifiers.getModality(isClassOrObject = false)).apply {
isInline = propertyModifiers.hasInline() || modifiers.hasInline()
isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal()
isLateInit = modifiers.hasLateinit()
}
}
@@ -463,6 +463,7 @@ open class RawFirBuilder(
declaration?.hasModifier(INLINE_KEYWORD) == true
isExternal = property.hasModifier(EXTERNAL_KEYWORD) ||
declaration?.hasModifier(EXTERNAL_KEYWORD) == true
isLateInit = declaration?.hasModifier(LATEINIT_KEYWORD) == true
}
}
@@ -198,7 +198,12 @@ val possibleTargetMap = mapOf(
REIFIED_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER),
VARARG_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER, KotlinTarget.PROPERTY_PARAMETER),
COMPANION_KEYWORD to EnumSet.of(KotlinTarget.OBJECT),
LATEINIT_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY, KotlinTarget.LOCAL_VARIABLE),
LATEINIT_KEYWORD to EnumSet.of(
KotlinTarget.MEMBER_PROPERTY,
KotlinTarget.TOP_LEVEL_PROPERTY,
KotlinTarget.LOCAL_VARIABLE,
KotlinTarget.BACKING_FIELD
),
DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS),
INLINE_KEYWORD to EnumSet.of(
KotlinTarget.FUNCTION,
@@ -2418,6 +2418,24 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.LATEINIT_PROPERTY_FIELD_DECLARATION_WITH_INITIALIZER) { firDiagnostic ->
LateinitPropertyFieldDeclarationWithInitializerImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.LATEINIT_FIELD_IN_VAL_PROPERTY) { firDiagnostic ->
LateinitFieldInValPropertyImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.LATEINIT_NULLABLE_BACKING_FIELD) { firDiagnostic ->
LateinitNullableBackingFieldImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.PROPERTY_MUST_HAVE_GETTER) { firDiagnostic ->
PropertyMustHaveGetterImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -1711,6 +1711,18 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = PropertyFieldDeclarationMissingInitializer::class
}
abstract class LateinitPropertyFieldDeclarationWithInitializer : KtFirDiagnostic<KtBackingField>() {
override val diagnosticClass get() = LateinitPropertyFieldDeclarationWithInitializer::class
}
abstract class LateinitFieldInValProperty : KtFirDiagnostic<KtBackingField>() {
override val diagnosticClass get() = LateinitFieldInValProperty::class
}
abstract class LateinitNullableBackingField : KtFirDiagnostic<KtBackingField>() {
override val diagnosticClass get() = LateinitNullableBackingField::class
}
abstract class PropertyMustHaveGetter : KtFirDiagnostic<KtProperty>() {
override val diagnosticClass get() = PropertyMustHaveGetter::class
}
@@ -2753,6 +2753,27 @@ internal class PropertyFieldDeclarationMissingInitializerImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LateinitPropertyFieldDeclarationWithInitializerImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LateinitPropertyFieldDeclarationWithInitializer(), KtAbstractFirDiagnostic<KtBackingField> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LateinitFieldInValPropertyImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LateinitFieldInValProperty(), KtAbstractFirDiagnostic<KtBackingField> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LateinitNullableBackingFieldImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LateinitNullableBackingField(), KtAbstractFirDiagnostic<KtBackingField> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class PropertyMustHaveGetterImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
@@ -2767,43 +2788,6 @@ internal class PropertyMustHaveSetterImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class AbstractPropertyInPrimaryConstructorParametersImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.AbstractPropertyInPrimaryConstructorParameters(), KtAbstractFirDiagnostic<KtModifierListOwner> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalVariableWithTypeParametersWarningImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LocalVariableWithTypeParametersWarning(), KtAbstractFirDiagnostic<KtProperty> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalVariableWithTypeParametersImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LocalVariableWithTypeParameters(), KtAbstractFirDiagnostic<KtProperty> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class InapplicableBackingFieldVisibilityImpl(
override val modifier: KtModifierKeywordToken,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.InapplicableBackingFieldVisibility(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class InapplicableBackingFieldModifierImpl(
override val modifier: KtModifierKeywordToken,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.InapplicableBackingFieldModifier(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExplicitBackingFieldInInterfaceImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
@@ -2839,6 +2823,20 @@ internal class AbstractPropertyInPrimaryConstructorParametersImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalVariableWithTypeParametersWarningImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LocalVariableWithTypeParametersWarning(), KtAbstractFirDiagnostic<KtProperty> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalVariableWithTypeParametersImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.LocalVariableWithTypeParameters(), KtAbstractFirDiagnostic<KtProperty> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExpectedDeclarationWithBodyImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,