[FIR] Set actual modifier on implicitly actual primary constructors

... of annotations and inline classes.

#KT-60139 Fixed
This commit is contained in:
Kirill Rakhman
2023-07-25 14:11:12 +02:00
committed by Space Team
parent fb04356829
commit b0f1746012
5 changed files with 21 additions and 25 deletions
@@ -10,10 +10,7 @@ import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.expectForActual
import org.jetbrains.kotlin.fir.declarations.getSingleExpectForActualOrNull
import org.jetbrains.kotlin.fir.declarations.utils.isActual import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -32,6 +29,7 @@ object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() {
} }
private fun checkActualFunctionWithDefaultArguments(function: FirFunction, reporter: DiagnosticReporter, context: CheckerContext) { private fun checkActualFunctionWithDefaultArguments(function: FirFunction, reporter: DiagnosticReporter, context: CheckerContext) {
if (function.symbol.isAnnotationConstructor(context.session)) return
for (valueParameter in function.valueParameters) { for (valueParameter in function.valueParameters) {
if (valueParameter.defaultValue != null) { if (valueParameter.defaultValue != null) {
reporter.reportOn(valueParameter.source, FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS, context) reporter.reportOn(valueParameter.source, FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS, context)
@@ -122,7 +122,6 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
) { ) {
val symbol = declaration.symbol val symbol = declaration.symbol
val compatibilityToMembersMap = symbol.expectForActual ?: return val compatibilityToMembersMap = symbol.expectForActual ?: return
val session = context.session
checkAmbiguousExpects(symbol, compatibilityToMembersMap, symbol, context, reporter) checkAmbiguousExpects(symbol, compatibilityToMembersMap, symbol, context, reporter)
@@ -131,7 +130,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
if (compatibilityToMembersMap.allStrongIncompatibilities()) return if (compatibilityToMembersMap.allStrongIncompatibilities()) return
if (Compatible in compatibilityToMembersMap) { if (Compatible in compatibilityToMembersMap) {
if (checkActual && requireActualModifier(symbol, session)) { if (checkActual) {
reporter.reportOn(source, FirErrors.ACTUAL_MISSING, context) reporter.reportOn(source, FirErrors.ACTUAL_MISSING, context)
} }
return return
@@ -168,13 +167,15 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
} }
Compatible !in compatibilityToMembersMap -> { Compatible !in compatibilityToMembersMap -> {
reporter.reportOn( if (requireActualModifier(declaration.symbol, context.session)) {
source, reporter.reportOn(
FirErrors.ACTUAL_WITHOUT_EXPECT, source,
symbol, FirErrors.ACTUAL_WITHOUT_EXPECT,
compatibilityToMembersMap, symbol,
context compatibilityToMembersMap,
) context
)
}
} }
else -> {} else -> {}
@@ -550,7 +550,8 @@ class LightTreeRawFirDeclarationBuilder(
selfType.source, selfType.source,
classWrapper, classWrapper,
delegatedConstructorSource, delegatedConstructorSource,
containingClassIsExpectClass = status.isExpect containingClassIsExpectClass = status.isExpect,
isImplicitlyActual = status.isActual && (status.isInline || classKind == ClassKind.ANNOTATION_CLASS)
) )
val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor
firPrimaryConstructor?.let { declarations += it } firPrimaryConstructor?.let { declarations += it }
@@ -884,7 +885,8 @@ class LightTreeRawFirDeclarationBuilder(
classWrapper: ClassWrapper, classWrapper: ClassWrapper,
delegatedConstructorSource: KtLightSourceElement?, delegatedConstructorSource: KtLightSourceElement?,
isEnumEntry: Boolean = false, isEnumEntry: Boolean = false,
containingClassIsExpectClass: Boolean containingClassIsExpectClass: Boolean,
isImplicitlyActual: Boolean = false,
): PrimaryConstructor? { ): PrimaryConstructor? {
fun ClassKind.isEnumRelated(): Boolean = this == ClassKind.ENUM_CLASS || this == ClassKind.ENUM_ENTRY fun ClassKind.isEnumRelated(): Boolean = this == ClassKind.ENUM_CLASS || this == ClassKind.ENUM_ENTRY
val shouldGenerateImplicitConstructor = val shouldGenerateImplicitConstructor =
@@ -955,7 +957,7 @@ class LightTreeRawFirDeclarationBuilder(
} }
val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility, Modality.FINAL).apply { val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility, Modality.FINAL).apply {
isExpect = modifiers.hasExpect() || context.containerIsExpect isExpect = modifiers.hasExpect() || context.containerIsExpect
isActual = modifiers.hasActual() isActual = modifiers.hasActual() || isImplicitlyActual
isInner = classWrapper.isInner() isInner = classWrapper.isInner()
isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private
isFromEnumClass = classWrapper.isEnum() isFromEnumClass = classWrapper.isEnum()
@@ -983,6 +983,7 @@ open class PsiRawFirBuilder(
containingClassIsExpectClass, containingClassIsExpectClass,
copyConstructedTypeRefWithImplicitSource = true, copyConstructedTypeRefWithImplicitSource = true,
isErrorConstructor = !hasPrimaryConstructor, isErrorConstructor = !hasPrimaryConstructor,
isImplicitlyActual = container.status.isActual && (container.status.isInline || classKind == ClassKind.ANNOTATION_CLASS)
) )
container.declarations += firPrimaryConstructor container.declarations += firPrimaryConstructor
} }
@@ -1003,6 +1004,7 @@ open class PsiRawFirBuilder(
containingClassIsExpectClass: Boolean, containingClassIsExpectClass: Boolean,
copyConstructedTypeRefWithImplicitSource: Boolean, copyConstructedTypeRefWithImplicitSource: Boolean,
isErrorConstructor: Boolean = false, isErrorConstructor: Boolean = false,
isImplicitlyActual: Boolean = false,
): FirConstructor { ): FirConstructor {
val constructorSource = this?.toFirSourceElement() val constructorSource = this?.toFirSourceElement()
?: owner.toKtPsiSourceElement(KtFakeSourceElementKind.ImplicitConstructor) ?: owner.toKtPsiSourceElement(KtFakeSourceElementKind.ImplicitConstructor)
@@ -1050,7 +1052,7 @@ open class PsiRawFirBuilder(
val explicitVisibility = this?.visibility?.takeUnless { it == Visibilities.Unknown } val explicitVisibility = this?.visibility?.takeUnless { it == Visibilities.Unknown }
val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility(), Modality.FINAL).apply { val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility(), Modality.FINAL).apply {
isExpect = this@toFirConstructor?.hasExpectModifier() == true || this@PsiRawFirBuilder.context.containerIsExpect isExpect = this@toFirConstructor?.hasExpectModifier() == true || this@PsiRawFirBuilder.context.containerIsExpect
isActual = this@toFirConstructor?.hasActualModifier() == true isActual = this@toFirConstructor?.hasActualModifier() == true || isImplicitlyActual
isInner = owner.parent.parent !is KtScript && owner.hasModifier(INNER_KEYWORD) // a warning about inner script class is reported on the class itself isInner = owner.parent.parent !is KtScript && owner.hasModifier(INNER_KEYWORD) // a warning about inner script class is reported on the class itself
isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private
isFromEnumClass = owner.hasModifier(ENUM_KEYWORD) isFromEnumClass = owner.hasModifier(ENUM_KEYWORD)
@@ -83,7 +83,7 @@ open class FirExpectActualMatcherTransformer(
// ------------------------------------------------------ // ------------------------------------------------------
fun transformMemberDeclaration(memberDeclaration: FirMemberDeclaration) { fun transformMemberDeclaration(memberDeclaration: FirMemberDeclaration) {
if (!memberDeclaration.isActual && !memberDeclaration.isImplicitlyActual()) return if (!memberDeclaration.isActual) return
val actualSymbol = memberDeclaration.symbol val actualSymbol = memberDeclaration.symbol
// Regardless of whether any `expect` symbols are found for `memberDeclaration`, it must be assigned an `expectForActual` map. // Regardless of whether any `expect` symbols are found for `memberDeclaration`, it must be assigned an `expectForActual` map.
@@ -97,11 +97,4 @@ open class FirExpectActualMatcherTransformer(
) ?: mapOf() ) ?: mapOf()
memberDeclaration.expectForActual = expectForActualData memberDeclaration.expectForActual = expectForActualData
} }
// TODO KT-60139 Remove special handling when implicitly actual elements have the actual flag set.
private fun FirMemberDeclaration.isImplicitlyActual(): Boolean {
if (this !is FirPrimaryConstructor) return false
val klass = getContainingClass(session) ?: return false
return klass.isActual && (klass.isInline || klass.classKind == ClassKind.ANNOTATION_CLASS)
}
} }