[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.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty 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.hasExplicitBackingField
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.typeContext 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( private fun checkAsPropertyNotSubtype(
property: FirProperty, property: FirProperty,
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter reporter: DiagnosticReporter
) { ) {
if (property.isVar && property.setter == null) { if (property.isVar && property.setter.isNotExplicit) {
reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_SETTER, context) reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_SETTER, context)
} }
} }
@@ -60,7 +65,7 @@ object FirPropertyFieldTypeChecker : FirPropertyChecker() {
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter reporter: DiagnosticReporter
) { ) {
if (property.getter == null) { if (property.getter.isNotExplicit) {
reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_GETTER, context) reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_GETTER, context)
} }
} }
@@ -1132,24 +1132,19 @@ class DeclarationsConverter(
isExternal = modifiers.hasExternal() isExternal = modifiers.hasExternal()
} }
val hasExplicitBackingField = backingField !is FirDefaultPropertyBackingField
val convertedAccessors = accessors.map { val convertedAccessors = accessors.map {
convertGetterOrSetter(it, returnType, propertyVisibility, symbol, modifiers, hasExplicitBackingField) convertGetterOrSetter(it, returnType, propertyVisibility, symbol, modifiers)
} }
this.getter = convertedAccessors.find { it.isGetter } this.getter = convertedAccessors.find { it.isGetter }
?: if (!hasExplicitBackingField) { ?: FirDefaultPropertyGetter(
FirDefaultPropertyGetter( property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor), moduleData, FirDeclarationOrigin.Source, returnType, propertyVisibility, symbol,
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor), moduleData, FirDeclarationOrigin.Source, returnType, propertyVisibility, symbol, ).also {
).also { it.status = defaultAccessorStatus()
it.status = defaultAccessorStatus() it.initContainingClassAttr()
it.initContainingClassAttr()
}
} else {
null
} }
// NOTE: We still need the setter even for a val property so we can report errors (e.g., VAL_WITH_SETTER). // 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 } this.setter = convertedAccessors.find { it.isSetter }
?: if (isVar && !hasExplicitBackingField) { ?: if (isVar) {
FirDefaultPropertySetter( FirDefaultPropertySetter(
property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor), property.toFirSourceElement(FirFakeSourceElementKind.DefaultAccessor),
moduleData, moduleData,
@@ -1259,7 +1254,6 @@ class DeclarationsConverter(
propertyVisibility: Visibility, propertyVisibility: Visibility,
propertySymbol: FirPropertySymbol, propertySymbol: FirPropertySymbol,
propertyModifiers: Modifier, propertyModifiers: Modifier,
hasBackingField: Boolean,
): FirPropertyAccessor { ): FirPropertyAccessor {
var modifiers = Modifier() var modifiers = Modifier()
var isGetter = true var isGetter = true
@@ -1298,11 +1292,7 @@ class DeclarationsConverter(
isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal() isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal()
} }
val sourceElement = getterOrSetter.toFirSourceElement() val sourceElement = getterOrSetter.toFirSourceElement()
// If an explicit backing field is present, if (block == null && expression == null) {
// 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) {
return FirDefaultPropertyAccessor return FirDefaultPropertyAccessor
.createGetterOrSetter( .createGetterOrSetter(
sourceElement, sourceElement,
@@ -368,7 +368,6 @@ open class RawFirBuilder(
propertyTypeRef: FirTypeRef, propertyTypeRef: FirTypeRef,
propertySymbol: FirPropertySymbol, propertySymbol: FirPropertySymbol,
isGetter: Boolean, isGetter: Boolean,
hasExplicitBackingField: Boolean,
): FirPropertyAccessor? { ): FirPropertyAccessor? {
val accessorVisibility = val accessorVisibility =
if (this?.visibility != null && this.visibility != Visibilities.Unknown) this.visibility else property.visibility 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() this@RawFirBuilder.context.firFunctionTargets.removeLast()
} }
} }
// If an explicit backing field is present, isGetter || property.isVar -> {
// 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) -> {
// Default getter for val/var properties, and default setter for var properties. // Default getter for val/var properties, and default setter for var properties.
val propertySource = val propertySource =
this?.toFirSourceElement() ?: property.toFirPsiSourceElement(FirFakeSourceElementKind.DefaultAccessor) this?.toFirSourceElement() ?: property.toFirPsiSourceElement(FirFakeSourceElementKind.DefaultAccessor)
@@ -1531,20 +1526,17 @@ open class RawFirBuilder(
propertyType, propertyType,
) )
val hasExplicitBackingField = backingField !is FirDefaultPropertyBackingField
getter = this@toFirProperty.getter.toFirPropertyAccessor( getter = this@toFirProperty.getter.toFirPropertyAccessor(
this@toFirProperty, this@toFirProperty,
propertyType, propertyType,
propertySymbol = symbol, propertySymbol = symbol,
isGetter = true, isGetter = true
hasExplicitBackingField,
) )
setter = this@toFirProperty.setter.toFirPropertyAccessor( setter = this@toFirProperty.setter.toFirPropertyAccessor(
this@toFirProperty, this@toFirProperty,
propertyType, propertyType,
propertySymbol = symbol, propertySymbol = symbol,
isGetter = false, isGetter = false
hasExplicitBackingField,
) )
status = FirDeclarationStatusImpl(visibility, modality).apply { status = FirDeclarationStatusImpl(visibility, modality).apply {
@@ -151,10 +151,6 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
} }
property.transformBackingField(transformer, withExpectedType(property.returnTypeRef)) 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 val delegate = property.delegate
if (delegate != null) { if (delegate != null) {
transformPropertyAccessorsWithDelegate(property, delegate) 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 { fun FirProperty.getDefaultAccessorStatus(): FirDeclarationStatus {
// Downward propagation of `inline` and `external` modifiers (from property to its accessors) // Downward propagation of `inline` and `external` modifiers (from property to its accessors)
return FirDeclarationStatusImpl(this.visibility, this.modality).apply { return FirDeclarationStatusImpl(this.visibility, this.modality).apply {