[FIR] Make default accessors always present
This commit is contained in:
committed by
TeamCityServer
parent
cc0d63117a
commit
30e52186eb
+7
-2
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-18
@@ -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 {
|
||||||
|
|||||||
-48
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user