diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KaFirNamedClassSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KaFirNamedClassSymbol.kt index cad833df05af1..1c779ea57a246 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KaFirNamedClassSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KaFirNamedClassSymbol.kt @@ -114,7 +114,7 @@ internal class KaFirNamedClassSymbol private constructor( if (backingPsi != null) { backingPsi.hasModifier(KtTokens.VALUE_KEYWORD) || backingPsi.hasModifier(KtTokens.INLINE_KEYWORD) } else { - firSymbol.isInline || firSymbol.isValue + firSymbol.isInlineOrValue } } diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmFieldApplicabilityChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmFieldApplicabilityChecker.kt index ca2a8ca7b42ea..1ebac403b4a41 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmFieldApplicabilityChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmFieldApplicabilityChecker.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId -import org.jetbrains.kotlin.fir.declarations.isInlineOrValueClass import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration @@ -102,7 +101,7 @@ object FirJvmFieldApplicabilityChecker : FirPropertyChecker(MppCheckerKind.Commo private fun FirTypeRef.isInlineClassThatRequiresMangling(session: FirSession): Boolean { val symbol = this.coneType.toRegularClassSymbol(session) ?: return false - return symbol.isInlineOrValueClass() && !symbol.isDontMangleClass() + return symbol.isInlineOrValue && !symbol.isDontMangleClass() } private fun FirRegularClassSymbol.isDontMangleClass(): Boolean { diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmInlineApplicabilityChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmInlineApplicabilityChecker.kt index b2a92c37319d9..e31f4e342c3c0 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmInlineApplicabilityChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmInlineApplicabilityChecker.kt @@ -14,12 +14,14 @@ import org.jetbrains.kotlin.fir.analysis.checkers.getModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.declarations.utils.SuspiciousValueClassCheck import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isValue import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_CLASS_ID object FirJvmInlineApplicabilityChecker : FirRegularClassChecker(MppCheckerKind.Common) { + @OptIn(SuspiciousValueClassCheck::class) override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { val annotation = declaration.getAnnotationByClassId(JVM_INLINE_ANNOTATION_CLASS_ID, context.session) if (annotation != null && !declaration.isValue) { diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt index 6c8b0c3db0752..fbd420acd27bf 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirSynchronizedAnnotationChecker.kt @@ -19,8 +19,8 @@ import org.jetbrains.kotlin.fir.declarations.FirFunction import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId import org.jetbrains.kotlin.fir.declarations.utils.isAbstract import org.jetbrains.kotlin.fir.declarations.utils.isInline +import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue import org.jetbrains.kotlin.fir.declarations.utils.isSuspend -import org.jetbrains.kotlin.fir.declarations.utils.isValue import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isSuspendOrKSuspendFunctionType import org.jetbrains.kotlin.name.JvmStandardClassIds.SYNCHRONIZED_ANNOTATION_CLASS_ID @@ -47,7 +47,7 @@ object FirSynchronizedAnnotationChecker : FirFunctionChecker(MppCheckerKind.Comm reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_IN_INTERFACE, context) containingClass.classKind == ClassKind.ANNOTATION_CLASS -> reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_IN_ANNOTATION, context) - containingClass.isInline || containingClass.isValue -> + containingClass.isInlineOrValue -> reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_VALUE_CLASS, context) declaration.isAbstract -> reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT, context) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt index 8082e6146afee..4c7cec48742a0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.collectUpperBounds import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass -import org.jetbrains.kotlin.fir.declarations.isInlineOrValueClass import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.isPrimitiveType import org.jetbrains.kotlin.fir.languageVersionSettings @@ -441,7 +440,7 @@ object ConeTypeCompatibilityChecker { firClass.isPrimitiveType() || (ctx.prohibitComparisonOfIncompatibleClasses && firClass.classId == StandardClassIds.KClass) || firClass.classId == StandardClassIds.String || firClass.classId == StandardClassIds.Unit || - (firClass is FirRegularClassSymbol && (firClass.isData || firClass.isInlineOrValueClass())) + (firClass is FirRegularClassSymbol && (firClass.isData || firClass.isInlineOrValue)) } private val FirClassSymbol<*>.isFinal: Boolean diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index ff6305d8befcb..76dacc4176f59 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -120,8 +120,8 @@ fun FirClassSymbol<*>.isSupertypeOf(other: FirClassSymbol<*>, session: FirSessio } fun ConeKotlinType.isValueClass(session: FirSession): Boolean { - // Value classes have inline modifier in FIR - return toRegularClassSymbol(session)?.isInlineOrValueClass() == true + // Value classes have `inline` or `value` modifier in FIR + return toRegularClassSymbol(session)?.isInlineOrValue == true } fun ConeKotlinType.isSingleFieldValueClass(session: FirSession): Boolean = with(session.typeContext) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt index 418b5fac29294..bc58396676502 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirTypeCompatibilityHelpers.kt @@ -73,7 +73,7 @@ internal fun ConeKotlinType.toTypeInfo(session: FirSession): TypeInfo { isEnumClass = boundsSymbols.any { it.isEnumClass }, isPrimitive = bounds.any { it.isPrimitiveOrNullablePrimitive }, isBuiltin = boundsSymbols.any { it.isBuiltin }, - isValueClass = boundsSymbols.any { it.isInline || it.isValue }, + isValueClass = boundsSymbols.any { it.isInlineOrValue }, isFinal = boundsSymbols.any { it.isFinalClass }, isClass = boundsSymbols.any { it.isClass }, // In K1's intersector, `canHaveSubtypes()` is called for `nullabilityStripped`. diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt index ebd353c7d2de2..910b6002fc743 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExpectActualDeclarationChecker.kt @@ -360,7 +360,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker(MppChecker symbol: FirBasedSymbol<*>, actualContainingClass: FirRegularClassSymbol, platformSession: FirSession - ): Boolean = (actualContainingClass.isInlineOrValueClass()) && + ): Boolean = (actualContainingClass.isInlineOrValue) && symbol is FirPropertySymbol && symbol.receiverParameter == null && actualContainingClass.primaryConstructorSymbol(platformSession)?.valueParameterSymbols?.singleOrNull()?.name == symbol.name diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt index cbee97e27de8e..4c8d535afcea2 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt @@ -8,9 +8,8 @@ package org.jetbrains.kotlin.fir.declarations import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.containingClassLookupTag -import org.jetbrains.kotlin.fir.declarations.utils.isInline +import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue import org.jetbrains.kotlin.fir.declarations.utils.isSuspend -import org.jetbrains.kotlin.fir.declarations.utils.isValue import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.defaultType @@ -108,7 +107,7 @@ object OperatorFunctionChecks { } return buildString { append("must override 'equals()' in Any") - if (customEqualsSupported && containingClassSymbol.isInlineOrValueClass()) { + if (customEqualsSupported && containingClassSymbol.isInlineOrValue) { val expectedParameterTypeRendered = containingClassSymbol.defaultType().replaceArgumentsWithStarProjections().renderReadable() append(" or define 'equals(other: ${expectedParameterTypeRendered}): Boolean'") diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt index bc30e7fcafc7e..b700a433e321d 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt @@ -76,7 +76,7 @@ fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean = with(this@isTypedEqualsInValueClass) { contextParameters.isEmpty() && receiverParameter == null && name == OperatorNameConventions.EQUALS - && this@run.isInlineOrValueClass() && valueParameters.size == 1 + && this@run.isInlineOrValue && valueParameters.size == 1 && returnTypeRef.coneType.fullyExpandedType(session).let { it.isBoolean || it.isNothing } && valueParameters[0].returnTypeRef.coneType.let { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt index 59f68b766000c..e6f311f5c7167 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt @@ -7,8 +7,7 @@ package org.jetbrains.kotlin.fir.declarations import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.utils.isInline -import org.jetbrains.kotlin.fir.declarations.utils.isValue +import org.jetbrains.kotlin.fir.declarations.utils.isInlineOrValue import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope @@ -76,7 +75,7 @@ fun FirConstructorSymbol.getConstructedClass(session: FirSession): FirRegularCla fun FirRegularClassSymbol.isInlineOrValueClass(): Boolean { if (this.classKind != ClassKind.CLASS) return false - return isInline || isValue + return isInlineOrValue } @PrivateForInline diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt index e7c29bc027959..b794c13a67129 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirStatusUtils.kt @@ -38,8 +38,16 @@ inline val FirMemberDeclaration.isOverride: Boolean get() = status.isOverride inline val FirMemberDeclaration.isOperator: Boolean get() = status.isOperator inline val FirMemberDeclaration.isInfix: Boolean get() = status.isInfix inline val FirMemberDeclaration.isInline: Boolean get() = status.isInline + +@RequiresOptIn(message = "Please consider using isInlineOrValue, as separate isInline or isValue calls don't cover other case") +annotation class SuspiciousValueClassCheck + +@SuspiciousValueClassCheck inline val FirClass.isValue: Boolean get() = status.isValue + +@OptIn(SuspiciousValueClassCheck::class) inline val FirClass.isInlineOrValue: Boolean get() = status.isInline || status.isValue + inline val FirMemberDeclaration.isTailRec: Boolean get() = status.isTailRec inline val FirMemberDeclaration.isExternal: Boolean get() = status.isExternal inline val FirMemberDeclaration.isSuspend: Boolean get() = status.isSuspend diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt index 2cd9a5285df91..986ba26049a8c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirSymbolStatusUtils.kt @@ -48,8 +48,16 @@ inline val FirClassLikeSymbol<*>.isActual: Boolean get() = rawStatus.isActual inline val FirClassLikeSymbol<*>.isExpect: Boolean get() = rawStatus.isExpect inline val FirClassLikeSymbol<*>.isInner: Boolean get() = rawStatus.isInner inline val FirClassLikeSymbol<*>.isStatic: Boolean get() = rawStatus.isStatic + +@SuspiciousValueClassCheck inline val FirClassLikeSymbol<*>.isInline: Boolean get() = rawStatus.isInline + +@SuspiciousValueClassCheck inline val FirClassLikeSymbol<*>.isValue: Boolean get() = rawStatus.isValue + +@OptIn(SuspiciousValueClassCheck::class) +inline val FirClassLikeSymbol<*>.isInlineOrValue: Boolean get() = isInline || isValue + inline val FirClassLikeSymbol<*>.isExternal: Boolean get() = rawStatus.isExternal inline val FirClassLikeSymbol<*>.isFromSealedClass: Boolean get() = rawStatus.isFromSealedClass inline val FirClassLikeSymbol<*>.isFromEnumClass: Boolean get() = rawStatus.isFromEnumClass diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirAllModifierRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirAllModifierRenderer.kt index 5a4ac4f0c73cc..873f508aa84b5 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirAllModifierRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/renderer/FirAllModifierRenderer.kt @@ -53,6 +53,7 @@ class FirAllModifierRenderer : FirModifierRenderer() { if (memberDeclaration.isInline) { renderModifier("inline") } + @OptIn(SuspiciousValueClassCheck::class) if (memberDeclaration is FirClass && memberDeclaration.isValue) { renderModifier("value") } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt index c6cd3b5e57ce9..b8c4516512f2f 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/checkers/FirSerializationPluginClassChecker.kt @@ -314,7 +314,7 @@ object FirSerializationPluginClassChecker : FirClassChecker(MppCheckerKind.Commo return false } - if ((classSymbol.isInline || classSymbol.isValue) && !session.versionReader.canSupportInlineClasses) { + if (classSymbol.isInlineOrValue && !session.versionReader.canSupportInlineClasses) { reporter.reportOn( classSymbol.serializableOrMetaAnnotationSource(session), FirSerializationErrors.INLINE_CLASSES_NOT_SUPPORTED,