[FIR] Make default accessors always present

This commit is contained in:
Nikolay Lunyak
2021-08-23 19:13:21 +03:00
committed by TeamCityServer
parent cc0d63117a
commit 30e52186eb
4 changed files with 18 additions and 79 deletions
@@ -10,6 +10,8 @@ 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.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.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.typeContext
@@ -45,12 +47,15 @@ object FirPropertyFieldTypeChecker : FirPropertyChecker() {
}
}
private val FirPropertyAccessor?.isNotExplicit
get() = this == null || this is FirDefaultPropertyAccessor
private fun checkAsPropertyNotSubtype(
property: FirProperty,
context: CheckerContext,
reporter: DiagnosticReporter
) {
if (property.isVar && property.setter == null) {
if (property.isVar && property.setter.isNotExplicit) {
reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_SETTER, context)
}
}
@@ -60,7 +65,7 @@ object FirPropertyFieldTypeChecker : FirPropertyChecker() {
context: CheckerContext,
reporter: DiagnosticReporter
) {
if (property.getter == null) {
if (property.getter.isNotExplicit) {
reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_GETTER, context)
}
}
@@ -1132,24 +1132,19 @@ class DeclarationsConverter(
isExternal = modifiers.hasExternal()
}
val hasExplicitBackingField = backingField !is FirDefaultPropertyBackingField
val convertedAccessors = accessors.map {
convertGetterOrSetter(it, returnType, propertyVisibility, symbol, modifiers, hasExplicitBackingField)
convertGetterOrSetter(it, returnType, propertyVisibility, symbol, modifiers)
}
this.getter = convertedAccessors.find { it.isGetter }
?: if (!hasExplicitBackingField) {
FirDefaultPropertyGetter(
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor), moduleData, FirDeclarationOrigin.Source, returnType, propertyVisibility, symbol,
).also {
it.status = defaultAccessorStatus()
it.initContainingClassAttr()
}
} else {
null
?: FirDefaultPropertyGetter(
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor), moduleData, FirDeclarationOrigin.Source, returnType, propertyVisibility, symbol,
).also {
it.status = defaultAccessorStatus()
it.initContainingClassAttr()
}
// NOTE: We still need the setter even for a val property so we can report errors (e.g., VAL_WITH_SETTER).
this.setter = convertedAccessors.find { it.isSetter }
?: if (isVar && !hasExplicitBackingField) {
?: if (isVar) {
FirDefaultPropertySetter(
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor),
moduleData,
@@ -1259,7 +1254,6 @@ class DeclarationsConverter(
propertyVisibility: Visibility,
propertySymbol: FirPropertySymbol,
propertyModifiers: Modifier,
hasBackingField: Boolean,
): FirPropertyAccessor {
var modifiers = Modifier()
var isGetter = true
@@ -1298,11 +1292,7 @@ class DeclarationsConverter(
isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal()
}
val sourceElement = getterOrSetter.toFirSourceElement()
// If an explicit backing field is present,
// the default accessors might not be compatible
// with it. We should check the types first, and
// only then see if we can create the default accessors.
if (block == null && expression == null && !hasBackingField) {
if (block == null && expression == null) {
return FirDefaultPropertyAccessor
.createGetterOrSetter(
sourceElement,
@@ -368,7 +368,6 @@ open class RawFirBuilder(
propertyTypeRef: FirTypeRef,
propertySymbol: FirPropertySymbol,
isGetter: Boolean,
hasExplicitBackingField: Boolean,
): FirPropertyAccessor? {
val accessorVisibility =
if (this?.visibility != null && this.visibility != Visibilities.Unknown) this.visibility else property.visibility
@@ -425,11 +424,7 @@ open class RawFirBuilder(
this@RawFirBuilder.context.firFunctionTargets.removeLast()
}
}
// If an explicit backing field is present,
// the default accessors might not be compatible
// with it. We should check the types first, and
// only then see if we can create the default accessors.
!hasExplicitBackingField && (isGetter || property.isVar) -> {
isGetter || property.isVar -> {
// Default getter for val/var properties, and default setter for var properties.
val propertySource =
this?.toFirSourceElement() ?: property.toFirPsiSourceElement(FirFakeSourceElementKind.DefaultAccessor)
@@ -1531,20 +1526,17 @@ open class RawFirBuilder(
propertyType,
)
val hasExplicitBackingField = backingField !is FirDefaultPropertyBackingField
getter = this@toFirProperty.getter.toFirPropertyAccessor(
this@toFirProperty,
propertyType,
propertySymbol = symbol,
isGetter = true,
hasExplicitBackingField,
isGetter = true
)
setter = this@toFirProperty.setter.toFirPropertyAccessor(
this@toFirProperty,
propertyType,
propertySymbol = symbol,
isGetter = false,
hasExplicitBackingField,
isGetter = false
)
status = FirDeclarationStatusImpl(visibility, modality).apply {
@@ -151,10 +151,6 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
property.transformBackingField(transformer, withExpectedType(property.returnTypeRef))
}
// In case an explicit backing field declaration
// is present, and the default accessors haven't
// been generated earlier.
property.generateMissingDefaultAccessors()
val delegate = property.delegate
if (delegate != null) {
transformPropertyAccessorsWithDelegate(property, delegate)
@@ -185,50 +181,6 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
}
private fun FirProperty.generateMissingDefaultAccessors() {
val fieldDeclaration = backingField ?: return
if (
!this.hasExplicitBackingField ||
fieldDeclaration.returnTypeRef !is FirResolvedTypeRef
) {
return
}
val typeCheckerContext = session.typeContext.newBaseTypeCheckerContext(
errorTypesEqualToAnything = false,
stubTypesEqualToAnything = false
)
if (getter == null && fieldDeclaration.isSubtypeOf(this, typeCheckerContext)) {
this.replaceGetter(
FirDefaultPropertyGetter(
null,
this.moduleData,
FirDeclarationOrigin.Source,
this.returnTypeRef,
this.visibility,
this.symbol,
).also {
it.status = this.getDefaultAccessorStatus()
}
)
} else if (this.isVar && this.isSubtypeOf(fieldDeclaration, typeCheckerContext)) {
this.replaceSetter(
FirDefaultPropertySetter(
null,
this.moduleData,
FirDeclarationOrigin.Source,
this.returnTypeRef,
this.visibility,
this.symbol,
).also {
it.status = this.getDefaultAccessorStatus()
}
)
}
}
fun FirProperty.getDefaultAccessorStatus(): FirDeclarationStatus {
// Downward propagation of `inline` and `external` modifiers (from property to its accessors)
return FirDeclarationStatusImpl(this.visibility, this.modality).apply {