[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.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
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.*
import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -32,6 +29,7 @@ object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() {
}
private fun checkActualFunctionWithDefaultArguments(function: FirFunction, reporter: DiagnosticReporter, context: CheckerContext) {
if (function.symbol.isAnnotationConstructor(context.session)) return
for (valueParameter in function.valueParameters) {
if (valueParameter.defaultValue != null) {
reporter.reportOn(valueParameter.source, FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS, context)
@@ -122,7 +122,6 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
) {
val symbol = declaration.symbol
val compatibilityToMembersMap = symbol.expectForActual ?: return
val session = context.session
checkAmbiguousExpects(symbol, compatibilityToMembersMap, symbol, context, reporter)
@@ -131,7 +130,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
if (compatibilityToMembersMap.allStrongIncompatibilities()) return
if (Compatible in compatibilityToMembersMap) {
if (checkActual && requireActualModifier(symbol, session)) {
if (checkActual) {
reporter.reportOn(source, FirErrors.ACTUAL_MISSING, context)
}
return
@@ -168,13 +167,15 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
}
Compatible !in compatibilityToMembersMap -> {
reporter.reportOn(
source,
FirErrors.ACTUAL_WITHOUT_EXPECT,
symbol,
compatibilityToMembersMap,
context
)
if (requireActualModifier(declaration.symbol, context.session)) {
reporter.reportOn(
source,
FirErrors.ACTUAL_WITHOUT_EXPECT,
symbol,
compatibilityToMembersMap,
context
)
}
}
else -> {}
@@ -550,7 +550,8 @@ class LightTreeRawFirDeclarationBuilder(
selfType.source,
classWrapper,
delegatedConstructorSource,
containingClassIsExpectClass = status.isExpect
containingClassIsExpectClass = status.isExpect,
isImplicitlyActual = status.isActual && (status.isInline || classKind == ClassKind.ANNOTATION_CLASS)
)
val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor
firPrimaryConstructor?.let { declarations += it }
@@ -884,7 +885,8 @@ class LightTreeRawFirDeclarationBuilder(
classWrapper: ClassWrapper,
delegatedConstructorSource: KtLightSourceElement?,
isEnumEntry: Boolean = false,
containingClassIsExpectClass: Boolean
containingClassIsExpectClass: Boolean,
isImplicitlyActual: Boolean = false,
): PrimaryConstructor? {
fun ClassKind.isEnumRelated(): Boolean = this == ClassKind.ENUM_CLASS || this == ClassKind.ENUM_ENTRY
val shouldGenerateImplicitConstructor =
@@ -955,7 +957,7 @@ class LightTreeRawFirDeclarationBuilder(
}
val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility, Modality.FINAL).apply {
isExpect = modifiers.hasExpect() || context.containerIsExpect
isActual = modifiers.hasActual()
isActual = modifiers.hasActual() || isImplicitlyActual
isInner = classWrapper.isInner()
isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private
isFromEnumClass = classWrapper.isEnum()
@@ -983,6 +983,7 @@ open class PsiRawFirBuilder(
containingClassIsExpectClass,
copyConstructedTypeRefWithImplicitSource = true,
isErrorConstructor = !hasPrimaryConstructor,
isImplicitlyActual = container.status.isActual && (container.status.isInline || classKind == ClassKind.ANNOTATION_CLASS)
)
container.declarations += firPrimaryConstructor
}
@@ -1003,6 +1004,7 @@ open class PsiRawFirBuilder(
containingClassIsExpectClass: Boolean,
copyConstructedTypeRefWithImplicitSource: Boolean,
isErrorConstructor: Boolean = false,
isImplicitlyActual: Boolean = false,
): FirConstructor {
val constructorSource = this?.toFirSourceElement()
?: owner.toKtPsiSourceElement(KtFakeSourceElementKind.ImplicitConstructor)
@@ -1050,7 +1052,7 @@ open class PsiRawFirBuilder(
val explicitVisibility = this?.visibility?.takeUnless { it == Visibilities.Unknown }
val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility(), Modality.FINAL).apply {
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
isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private
isFromEnumClass = owner.hasModifier(ENUM_KEYWORD)
@@ -83,7 +83,7 @@ open class FirExpectActualMatcherTransformer(
// ------------------------------------------------------
fun transformMemberDeclaration(memberDeclaration: FirMemberDeclaration) {
if (!memberDeclaration.isActual && !memberDeclaration.isImplicitlyActual()) return
if (!memberDeclaration.isActual) return
val actualSymbol = memberDeclaration.symbol
// 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()
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)
}
}