[IR] Add diagnostics to forbid annotations for MFVC-typed elements

Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com>

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2022-10-21 06:23:33 +02:00
committed by Space Team
parent adee33d3e5
commit fa4ceb4ef4
28 changed files with 353 additions and 56 deletions
@@ -1406,6 +1406,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET) { firDiagnostic ->
AnnotationOnIllegalMultiFieldValueClassTypedTargetImpl(
firDiagnostic.a,
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.NONE_APPLICABLE) { firDiagnostic ->
NoneApplicableImpl(
firDiagnostic.a.map { firBasedSymbol ->
@@ -1012,6 +1012,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ValueClassCannotBeCloneable::class
}
abstract class AnnotationOnIllegalMultiFieldValueClassTypedTarget : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = AnnotationOnIllegalMultiFieldValueClassTypedTarget::class
abstract val name: String
}
abstract class NoneApplicable : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = NoneApplicable::class
abstract val candidates: List<KtSymbol>
@@ -1214,6 +1214,12 @@ internal class ValueClassCannotBeCloneableImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.ValueClassCannotBeCloneable(), KtAbstractFirDiagnostic<KtDeclaration>
internal class AnnotationOnIllegalMultiFieldValueClassTypedTargetImpl(
override val name: String,
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.AnnotationOnIllegalMultiFieldValueClassTypedTarget(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class NoneApplicableImpl(
override val candidates: List<KtSymbol>,
override val firDiagnostic: KtPsiDiagnostic,
@@ -33612,6 +33612,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/valueClasses"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/annotations.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithUniversal());
}
@Test
@TestMetadata("basicValueClassDeclaration.kt")
public void testBasicValueClassDeclaration() throws Exception {
@@ -33708,6 +33708,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/valueClasses"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/annotations.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithUniversal());
}
@Test
@TestMetadata("basicValueClassDeclaration.kt")
public void testBasicValueClassDeclaration() throws Exception {
@@ -33612,6 +33612,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/valueClasses"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/annotations.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithUniversal());
}
@Test
@TestMetadata("basicValueClassDeclaration.kt")
public void testBasicValueClassDeclaration() throws Exception {
@@ -434,6 +434,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val TYPE_ARGUMENT_ON_TYPED_VALUE_CLASS_EQUALS by error<KtTypeReference>()
val INNER_CLASS_INSIDE_VALUE_CLASS by error<KtDeclaration>(PositioningStrategy.INNER_MODIFIER)
val VALUE_CLASS_CANNOT_BE_CLONEABLE by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
val ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET by error<KtAnnotationEntry> {
parameter<String>("name")
}
}
val APPLICABILITY by object : DiagnosticGroup("Applicability") {
@@ -5,21 +5,22 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.JvmFieldApplicabilityProblem.*
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.needsMultiFieldValueClassFlattening
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirProperty
@@ -65,7 +66,8 @@ object FirJvmFieldApplicabilityChecker : FirPropertyChecker() {
}
containingClassSymbol == null && isInsideJvmMultifileClassFile(context) ->
TOP_LEVEL_PROPERTY_OF_MULTIFILE_FACADE
declaration.returnTypeRef.isInlineClassThatRequiresMangling(session) -> RETURN_TYPE_IS_INLINE_CLASS
declaration.returnTypeRef.isInlineClassThatRequiresMangling(session) -> RETURN_TYPE_IS_VALUE_CLASS
declaration.returnTypeRef.needsMultiFieldValueClassFlattening(session) -> RETURN_TYPE_IS_VALUE_CLASS
else -> return
}
@@ -48,7 +48,7 @@ object FirJvmNameChecker : FirBasicDeclarationChecker() {
if (
declaration.isOverride ||
declaration.isOpen ||
containingClass?.isInlineThatRequiresMangling() == true
containingClass?.isValueClassThatRequiresMangling() == true
) {
reporter.reportOn(jvmName.source, FirJvmErrors.INAPPLICABLE_JVM_NAME, context)
}
@@ -66,7 +66,8 @@ object FirJvmNameChecker : FirBasicDeclarationChecker() {
return containingClass != null || !function.symbol.callableId.isLocal
}
private fun FirRegularClass.isInlineThatRequiresMangling(): Boolean {
private fun FirRegularClass.isValueClassThatRequiresMangling(): Boolean {
// value classes have inline modifiers in FIR
return isInline && name != StandardClassIds.Result.shortClassName
}
}
@@ -327,6 +327,7 @@ object FirErrors {
val TYPE_ARGUMENT_ON_TYPED_VALUE_CLASS_EQUALS by error0<KtTypeReference>()
val INNER_CLASS_INSIDE_VALUE_CLASS by error0<KtDeclaration>(SourceElementPositioningStrategies.INNER_MODIFIER)
val VALUE_CLASS_CANNOT_BE_CLONEABLE by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
val ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET by error1<KtAnnotationEntry, String>()
// Applicability
val NONE_APPLICABLE by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.primaryConstructorSymbol
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.primaryConstructorSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.containingClassForLocalAttr
@@ -98,7 +97,33 @@ fun FirClassSymbol<*>.isSupertypeOf(other: FirClassSymbol<*>, session: FirSessio
return isSupertypeOf(other, mutableSetOf())
}
fun ConeKotlinType.isInlineClass(session: FirSession): Boolean = toRegularClassSymbol(session)?.isInline == true
fun ConeKotlinType.isValueClass(session: FirSession): Boolean {
// Value classes have inline modifier in FIR
return toRegularClassSymbol(session)?.isInline == true
}
fun ConeKotlinType.isSingleFieldValueClass(session: FirSession): Boolean = with(session.typeContext) {
isRecursiveSingleFieldValueClassType(session) || typeConstructor().isInlineClass()
}
fun ConeKotlinType.isRecursiveSingleFieldValueClassType(session: FirSession) =
isRecursiveValueClassType(hashSetOf(), session, onlyInline = true)
fun ConeKotlinType.isRecursiveValueClassType(session: FirSession) =
isRecursiveValueClassType(hashSetOf(), session, onlyInline = false)
private fun ConeKotlinType.isRecursiveValueClassType(visited: HashSet<ConeKotlinType>, session: FirSession, onlyInline: Boolean): Boolean {
val asRegularClass = this.toRegularClassSymbol(session)?.takeIf { it.isInlineOrValueClass() } ?: return false
val primaryConstructor = asRegularClass.declarationSymbols
.firstOrNull { it is FirConstructorSymbol && it.isPrimary } as FirConstructorSymbol?
?: return false
if (primaryConstructor.valueParameterSymbols.size > 1 && onlyInline) return false
return !visited.add(this) || primaryConstructor.valueParameterSymbols.any {
it.resolvedReturnTypeRef.coneType.isRecursiveValueClassType(visited, session, onlyInline)
}.also { visited.remove(this) }
}
/**
* Returns the FirRegularClass associated with this
@@ -678,6 +703,6 @@ private fun findDefaultValue(source: KtLightSourceElement): KtLightSourceElement
}
fun ConeKotlinType.getInlineClassUnderlyingType(session: FirSession): ConeKotlinType {
require(this.isInlineClass(session))
require(this.isSingleFieldValueClass(session))
return toRegularClassSymbol(session)!!.primaryConstructorSymbol()!!.valueParameterSymbols[0].resolvedReturnTypeRef.coneType
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.hasValOrVar
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.languageVersionSettings
@@ -70,6 +72,44 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
}
}
private fun checkMultiFieldValueClassAnnotationRestrictions(
declaration: FirDeclaration,
annotation: FirAnnotation,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val (hint, type) = when (annotation.useSiteTarget) {
FIELD, PROPERTY_DELEGATE_FIELD -> "fields" to ((declaration as? FirProperty)?.backingField?.returnTypeRef ?: return)
FILE, PROPERTY, PROPERTY_SETTER -> return
PROPERTY_GETTER -> "getters" to ((declaration as? FirPropertyAccessor)?.returnTypeRef ?: return)
RECEIVER -> "receivers" to ((declaration as? FirCallableDeclaration)?.receiverTypeRef ?: return)
CONSTRUCTOR_PARAMETER, SETTER_PARAMETER -> "parameters" to (declaration as? FirValueParameter ?: return).returnTypeRef
null -> when {
declaration is FirProperty && !declaration.isLocal -> {
val allowedAnnotationTargets = annotation.getAllowedAnnotationTargets(context.session)
when {
declaration.fromPrimaryConstructor == true && allowedAnnotationTargets.contains(KotlinTarget.VALUE_PARAMETER) -> return // handled in FirValueParameter case
allowedAnnotationTargets.contains(KotlinTarget.PROPERTY) -> return
allowedAnnotationTargets.contains(KotlinTarget.FIELD) -> "fields" to declaration.returnTypeRef
else -> return
}
}
declaration is FirField -> "fields" to declaration.returnTypeRef
declaration is FirValueParameter -> "parameters" to declaration.returnTypeRef
declaration is FirVariable -> "variables" to declaration.returnTypeRef
declaration is FirPropertyAccessor && declaration.isGetter &&
declaration.receiverTypeRef == null &&
declaration.contextReceivers.isEmpty() ->
"getters" to declaration.returnTypeRef
else -> return
}
}
if (type.needsMfvcFlattening(context.session)) {
reporter.reportOn(annotation.source, FirErrors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET, hint, context)
}
}
private fun checkAnnotationTarget(
declaration: FirDeclaration,
annotation: FirAnnotation,
@@ -96,6 +136,7 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
}
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted) || checkWithUseSiteTargets()) {
checkMultiFieldValueClassAnnotationRestrictions(declaration, annotation, context, reporter)
return
}
@@ -128,28 +169,28 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
) {
if (annotation.source?.kind == KtFakeSourceElementKind.FromUseSiteTarget) return
when (target) {
AnnotationUseSiteTarget.PROPERTY,
AnnotationUseSiteTarget.PROPERTY_GETTER -> {
PROPERTY,
PROPERTY_GETTER -> {
}
AnnotationUseSiteTarget.FIELD -> {
FIELD -> {
if (annotated is FirProperty && annotated.delegateFieldSymbol != null && !annotated.hasBackingField) {
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD, context)
}
}
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> {
PROPERTY_DELEGATE_FIELD -> {
if (annotated is FirProperty && annotated.delegateFieldSymbol == null) {
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, context)
}
}
AnnotationUseSiteTarget.PROPERTY_SETTER,
AnnotationUseSiteTarget.SETTER_PARAMETER -> {
PROPERTY_SETTER,
SETTER_PARAMETER -> {
if (annotated !is FirProperty || annotated.isLocal) {
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_ON_PROPERTY, target.renderName, context)
} else if (!annotated.isVar) {
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, target.renderName, context)
}
}
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> when {
CONSTRUCTOR_PARAMETER -> when {
annotated is FirValueParameter -> {
val container = context.containingDeclarations.lastOrNull()
if (container is FirConstructor && container.isPrimary) {
@@ -164,13 +205,13 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
}
else -> reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_PARAM_TARGET, context)
}
AnnotationUseSiteTarget.FILE -> {
FILE -> {
// NB: report once?
if (annotated !is FirFile) {
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_FILE_TARGET, context)
}
}
AnnotationUseSiteTarget.RECEIVER -> {
RECEIVER -> {
// NB: report once?
// annotation with use-site target `receiver` can be only on type reference, but not on declaration
reporter.reportOn(
@@ -245,9 +286,9 @@ object FirAnnotationChecker : FirBasicDeclarationChecker() {
}
val propertyAnnotations = mapOf(
AnnotationUseSiteTarget.PROPERTY_GETTER to property.getter?.getAnnotationTypes(),
AnnotationUseSiteTarget.PROPERTY_SETTER to property.setter?.getAnnotationTypes(),
AnnotationUseSiteTarget.SETTER_PARAMETER to property.setter?.valueParameters?.single().getAnnotationTypes()
PROPERTY_GETTER to property.getter?.getAnnotationTypes(),
PROPERTY_SETTER to property.setter?.getAnnotationTypes(),
SETTER_PARAMETER to property.setter?.valueParameters?.single().getAnnotationTypes()
)
val isError = context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitRepeatedUseSiteTargetAnnotations)
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtRealSourceElementKind
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineClass
import org.jetbrains.kotlin.fir.analysis.checkers.isValueClass
import org.jetbrains.kotlin.fir.analysis.checkers.valOrVarKeyword
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -66,7 +66,7 @@ object FirFunctionParameterChecker : FirFunctionChecker() {
for (varargParameter in varargParameters) {
val varargParameterType = varargParameter.returnTypeRef.coneType.arrayElementType() ?: continue
if (AbstractTypeChecker.isSubtypeOf(context.session.typeContext, varargParameterType, nullableNothingType) ||
(varargParameterType.isInlineClass(context.session) && !varargParameterType.isUnsignedTypeOrNullableUnsignedType)
(varargParameterType.isValueClass(context.session) && !varargParameterType.isUnsignedTypeOrNullableUnsignedType)
// Note: comparing with FE1.0, we skip checking if the type is not primitive because primitive types are not inline. That
// is any primitive values are already allowed by the inline check.
) {
@@ -11,15 +11,14 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirInlineClassDeclarationChecker.isRecursiveInlineClassType
import org.jetbrains.kotlin.fir.analysis.checkers.getInlineClassUnderlyingType
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineClass
import org.jetbrains.kotlin.fir.analysis.checkers.isRecursiveValueClassType
import org.jetbrains.kotlin.fir.analysis.checkers.isSingleFieldValueClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
import org.jetbrains.kotlin.fir.types.*
@@ -65,7 +64,7 @@ object FirInapplicableLateinitChecker : FirPropertyChecker() {
reporter.reportError(declaration.source, "is not allowed on properties with a custom getter or setter", context)
}
if (declaration.returnTypeRef.coneType.isInlineClass(context.session)) {
if (declaration.returnTypeRef.coneType.isSingleFieldValueClass(context.session)) {
val declarationType = declaration.returnTypeRef.coneType
val variables = if (declaration.isLocal) "local variables" else "properties"
when {
@@ -93,14 +92,14 @@ object FirInapplicableLateinitChecker : FirPropertyChecker() {
fun isForbiddenTypeForLateinit(type: ConeKotlinType): Boolean {
if (type.isPrimitiveOrNullablePrimitive) return true
if (type.hasNullableUpperBound) return true
if (type.isInlineClass(session)) {
if (type.isSingleFieldValueClass(session)) {
return isForbiddenTypeForLateinit(type.getInlineClassUnderlyingType(session))
}
return false
}
// prevent infinite recursion
if (type.isRecursiveInlineClassType(session)) return false
if (type.isRecursiveValueClassType(session)) return false
return isForbiddenTypeForLateinit(type.getInlineClassUnderlyingType(session))
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.checkers.isRecursiveValueClassType
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
@@ -23,7 +24,6 @@ import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.isEquals
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtTokens
@@ -197,7 +197,7 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() {
)
}
primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) -> {
primaryConstructorParameter.returnTypeRef.coneType.isRecursiveValueClassType(context.session) -> {
reporter.reportOn(
primaryConstructorParameter.returnTypeRef.source, FirErrors.VALUE_CLASS_CANNOT_BE_RECURSIVE,
context
@@ -276,21 +276,6 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() {
arrayElementType.isGenericArrayOfTypeParameter()
}
fun ConeKotlinType.isRecursiveInlineClassType(session: FirSession) =
isRecursiveInlineClassType(hashSetOf(), session)
private fun ConeKotlinType.isRecursiveInlineClassType(visited: HashSet<ConeKotlinType>, session: FirSession): Boolean {
val asRegularClass = this.toRegularClassSymbol(session)?.takeIf { it.isInlineOrValueClass() } ?: return false
val primaryConstructor = asRegularClass.declarationSymbols
.firstOrNull { it is FirConstructorSymbol && it.isPrimary } as FirConstructorSymbol?
?: return false
return !visited.add(this) || primaryConstructor.valueParameterSymbols.any {
it.resolvedReturnTypeRef.coneType.isRecursiveInlineClassType(visited, session)
}.also { visited.remove(this) }
}
private fun FirRegularClass.isSubtypeOfCloneable(session: FirSession): Boolean {
if (classId.isCloneableId()) return true
@@ -18,11 +18,8 @@ import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef
import org.jetbrains.kotlin.fir.types.isBoolean
import org.jetbrains.kotlin.fir.types.isNothing
import org.jetbrains.kotlin.fir.types.replaceArgumentsWithStarProjections
import org.jetbrains.kotlin.util.OperatorNameConventions
internal fun isInsideExpectClass(containingClass: FirClass, context: CheckerContext): Boolean {
@@ -131,6 +128,10 @@ fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean =
}
} ?: false
fun FirTypeRef.needsMultiFieldValueClassFlattening(session: FirSession) = with(session.typeContext) {
coneType.typeConstructor().isMultiFieldValueClass() && !coneType.isNullable
}
val FirCallableSymbol<*>.hasExplicitReturnType: Boolean
get() {
val returnTypeRef = resolvedReturnTypeRef
@@ -68,6 +68,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ARGUME
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_CONSTRUCTOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_IN_WHERE_CLAUSE_ERROR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_ON_SUPERCLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT
@@ -1290,6 +1291,12 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(TYPE_ARGUMENT_ON_TYPED_VALUE_CLASS_EQUALS, "Type arguments for typed value class equals must be only star projections")
map.put(INNER_CLASS_INSIDE_VALUE_CLASS, "Value class cannot have inner classes")
map.put(VALUE_CLASS_CANNOT_BE_CLONEABLE, "Value class cannot be Cloneable")
map.put(
ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET,
"Annotations on ''{0}'' of multi-field value class type are not supported",
STRING
)
// Inline
map.put(
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.JvmFieldApplicabilityProblem.*
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fileClasses.isInsideJvmMultifileClassFile
@@ -30,9 +31,9 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
import org.jetbrains.kotlin.JvmFieldApplicabilityProblem.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.jvm.isInlineClassThatRequiresMangling
import org.jetbrains.kotlin.resolve.needsMfvcFlattening
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -63,7 +64,8 @@ class JvmFieldApplicabilityChecker : DeclarationChecker {
}
DescriptorUtils.isTopLevelDeclaration(descriptor) && declaration.isInsideJvmMultifileClassFile() ->
TOP_LEVEL_PROPERTY_OF_MULTIFILE_FACADE
descriptor.returnType?.isInlineClassThatRequiresMangling() == true -> RETURN_TYPE_IS_INLINE_CLASS
descriptor.returnType?.isInlineClassThatRequiresMangling() == true -> RETURN_TYPE_IS_VALUE_CLASS
descriptor.returnType?.needsMfvcFlattening() == true -> RETURN_TYPE_IS_VALUE_CLASS
else -> return
}
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.annotations.findSynchronizedAnnotation
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
@@ -157,6 +158,8 @@ class JvmNameAnnotationChecker : DeclarationChecker {
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry))
} else if (descriptor.containingDeclaration.isInlineClassThatRequiresMangling()) {
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry))
} else if (descriptor.containingDeclaration.isMultiFieldValueClass()) {
diagnosticHolder.report(ErrorsJvm.INAPPLICABLE_JVM_NAME.on(annotationEntry))
}
}
}
@@ -430,6 +430,9 @@ public interface Errors {
DiagnosticFactory0<KtContextReceiverList> VALUE_CLASS_CANNOT_HAVE_CONTEXT_RECEIVERS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtNamedFunction, KotlinType> INEFFICIENT_EQUALS_OVERRIDING_IN_VALUE_CLASS =
DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
DiagnosticFactory1<KtAnnotationEntry, String> ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET =
DiagnosticFactory1.create(ERROR);
// Result class
@@ -806,6 +806,7 @@ public class DefaultErrorMessages {
MAP.put(INEFFICIENT_EQUALS_OVERRIDING_IN_VALUE_CLASS,
"Overriding ''equals'' from ''Any'' in value class without operator ''equals(other: {0}): Boolean'' leads to boxing on every equality comparison",
RENDER_TYPE);
MAP.put(ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET, "Annotations on {0} of multi-field value class type are not supported", STRING);
MAP.put(RESULT_CLASS_IN_RETURN_TYPE, "'kotlin.Result' cannot be used as a return type");
MAP.put(RESULT_CLASS_WITH_NULLABLE_OPERATOR, "Expression of type ''kotlin.Result'' cannot be used as a left operand of ''{0}''", STRING);
@@ -27,6 +27,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
KClassWithIncorrectTypeArgumentChecker,
SuspendLimitationsChecker,
ValueClassDeclarationChecker,
MultiFieldValueClassAnnotationsChecker,
PropertiesWithBackingFieldsInsideValueClass(),
InnerClassInsideValueClass(),
AnnotationClassTargetAndRetentionChecker(),
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.calls.util.getType
import org.jetbrains.kotlin.resolve.needsMfvcFlattening
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
object MultiFieldValueClassAnnotationsChecker : DeclarationChecker {
private fun report(context: DeclarationCheckerContext, name: String, type: KotlinType, annotationEntry: KtAnnotationEntry) {
if (!type.needsMfvcFlattening()) return
context.trace.report(Errors.ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET.on(annotationEntry, name))
}
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
fun report(name: String, type: KotlinType, annotations: Annotations) {
for (annotationDescriptor in annotations) {
report(context, name, type, annotationDescriptor.source.getPsi() as KtAnnotationEntry)
}
}
when (descriptor) {
is PropertyDescriptor -> {
descriptor.backingField?.let { report("fields", descriptor.type, it.annotations) }
val delegateType = (declaration as? KtProperty)?.delegateExpression?.getType(context.trace.bindingContext)
descriptor.delegateField?.let {
if (delegateType == null) return@let
report("delegate fields", delegateType, it.annotations)
}
descriptor.getter?.let { getterDescriptor ->
if (getterDescriptor.contextReceiverParameters.isNotEmpty() || getterDescriptor.extensionReceiverParameter != null) return@let
val type = getterDescriptor.returnType ?: return@let
report("getters", type, getterDescriptor.annotations)
}
descriptor.setter?.valueParameters?.single()?.let { report("parameters", it.type, it.annotations) }
descriptor.extensionReceiverParameter?.let { report("receivers", it.type, it.annotations) }
descriptor.contextReceiverParameters.forEach { report("receivers", it.type, it.annotations) }
}
is PropertyAccessorDescriptor -> Unit
is LocalVariableDescriptor -> {
report("variables", descriptor.type, descriptor.annotations)
}
is CallableDescriptor -> {
descriptor.extensionReceiverParameter?.let { report("receivers", it.type, it.annotations) }
descriptor.contextReceiverParameters.forEach { report("receivers", it.type, it.annotations) }
descriptor.valueParameters.forEach { report("parameters", it.type, it.annotations) }
}
}
}
}
@@ -0,0 +1,113 @@
// !LANGUAGE: +ValueClasses
// WITH_STDLIB
// SKIP_TXT
// WORKS_WHEN_VALUE_CLASS
// FIR_IDENTICAL
@Repeatable
annotation class Ann
@[Ann Ann]
@JvmInline
value class A @Ann constructor(
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
val x: Int,
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
val y: Int,
)
@[Ann Ann]
@JvmInline
value class B @Ann constructor(
@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@param:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@property:[Ann Ann]
@field:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@get:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val x: A,
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
val y: A?,
) {
<!INAPPLICABLE_JVM_NAME!>@JvmName("otherName")<!>
fun f() = Unit
}
@[Ann Ann]
class C @Ann constructor(
@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@param:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@property:[Ann Ann]
@field:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@get:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
@set:[Ann Ann]
@setparam:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
var x: A,
@[Ann Ann]
@param:[Ann Ann]
@property:[Ann Ann]
@field:[Ann Ann]
@get:[Ann Ann]
@set:[Ann Ann]
@setparam:[Ann Ann]
var y: A?,
) {
@delegate:[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val z by lazy { A(-100, -200) }
<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET, INAPPLICABLE_JVM_FIELD!>@JvmField<!>
val e = x
init {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val y = A(1, 2)
}
fun f() {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val y = A(1, 2)
}
}
}
}
@[Ann Ann]
fun @receiver:[Ann Ann] A.t(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] a: A, @[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] b: B, @[Ann Ann] c: C) {
if (2 + 2 == 4) {
@[Ann Ann]
val x = 4
@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val y = A(1, 2)
}
fun f() {
if (2 + 2 == 4) {
@[Ann Ann]
val x1 = 4
@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>]
val y1 = A(1, 2)
}
}
}
@[Ann Ann]
fun @receiver:[Ann Ann] C.t(@[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] a: A, @[<!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!> <!ANNOTATION_ON_ILLEGAL_MULTI_FIELD_VALUE_CLASS_TYPED_TARGET!>Ann<!>] b: B, @[Ann Ann] c: C) = 4
@@ -33708,6 +33708,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/valueClasses"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("annotations.kt")
public void testAnnotations() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/annotations.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithUniversal());
}
@Test
@TestMetadata("basicValueClassDeclaration.kt")
public void testBasicValueClassDeclaration() throws Exception {
@@ -18,5 +18,5 @@ enum class JvmFieldApplicabilityProblem(val errorMessage: String) {
NOT_PUBLIC_VAL_WITH_JVMFIELD("JvmField could be applied only if all interface companion properties are 'public final val' with '@JvmField' annotation"),
TOP_LEVEL_PROPERTY_OF_MULTIFILE_FACADE("JvmField cannot be applied to top level property of a file annotated with ${JVM_MULTIFILE_CLASS_SHORT}"),
DELEGATE("JvmField cannot be applied to delegated property"),
RETURN_TYPE_IS_INLINE_CLASS("JvmField cannot be applied to a property of an inline class type")
RETURN_TYPE_IS_VALUE_CLASS("JvmField cannot be applied to a property of a value class type"),
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.isNullableType
val JVM_INLINE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmInline")
val JVM_INLINE_ANNOTATION_CLASS_ID = ClassId.topLevel(JVM_INLINE_ANNOTATION_FQ_NAME)
@@ -42,6 +43,9 @@ fun KotlinType.unsubstitutedUnderlyingTypes(): List<KotlinType> {
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
fun KotlinType.needsMfvcFlattening(): Boolean =
constructor.declarationDescriptor?.run { isMultiFieldValueClass() && !isNullableType() } == true
fun KotlinType.substitutedUnderlyingType(): KotlinType? =
unsubstitutedUnderlyingType()?.let { TypeSubstitutor.create(this).substitute(it, Variance.INVARIANT) }
@@ -12,8 +12,7 @@ import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineClass
import org.jetbrains.kotlin.fir.analysis.checkers.outerClassSymbol
import org.jetbrains.kotlin.fir.analysis.checkers.isValueClass
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
@@ -481,7 +480,7 @@ object FirSerializationPluginClassChecker : FirClassChecker() {
context(CheckerContext)
@Suppress("IncorrectFormatting") // KTIJ-22227
private val ConeKotlinType.isUnsupportedInlineType: Boolean
get() = isInlineClass(session) && !isPrimitiveOrNullablePrimitive
get() = isValueClass(session) && !isPrimitiveOrNullablePrimitive
context(CheckerContext)
@Suppress("IncorrectFormatting") // KTIJ-22227