diff --git a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassConstructor.kt b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassConstructor.kt index b7cb51e89f2..5266114e6f5 100644 --- a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassConstructor.kt +++ b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassConstructor.kt @@ -1,4 +1,4 @@ -value class WithoutConstructor {} +value class WithoutConstructor {} inline class WithoutParameter() {} inline class WithTwoParameters(val x: Int, val y: String) {} diff --git a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt index 2e404e13523..a5cba659e5f 100644 --- a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt +++ b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassDeclaration.kt @@ -3,14 +3,14 @@ class A { fun foo() { inline class C(val x: Int) } - inner value class D(val x: Int) + inner value class D(val x: Int) } open inline class NotFinalClass1(val x: Int) abstract inline class NotFinalClass2(val x: Int) sealed inline class NotFinalClass3(val x: Int) -value class CloneableClass1(val x: Int): Cloneable +value class CloneableClass1(val x: Int): Cloneable inline class CloneableClass2(val x: Int): java.lang.Cloneable open class Test diff --git a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassMembers.kt b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassMembers.kt index 232d3212d0e..c51f4e6bf19 100644 --- a/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassMembers.kt +++ b/compiler/fir/analysis-tests/testData/resolve/inlineClasses/inlineClassMembers.kt @@ -1,4 +1,4 @@ -value class BackingFields(val x: Int) { +value class BackingFields(val x: Int) { val y = 0 var z: String get() = "" @@ -27,6 +27,6 @@ inline class SecondaryConstructors(val x: Int) { } } -value class WithInner(val x: String) { +value class WithInner(val x: String) { inner class Inner } diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt index 06caedf87ff..74c1734f162 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt @@ -37,6 +37,9 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { val ILLEGAL_JVM_NAME by error() val FUNCTION_DELEGATE_MEMBER_NAME_CLASH by error(PositioningStrategy.DECLARATION_NAME) + + val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error() + val JVM_INLINE_WITHOUT_VALUE_CLASS by error() } val TYPES by object : DiagnosticGroup("Types") { diff --git a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt index 08ad938f4c7..508958792de 100644 --- a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt +++ b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt @@ -40,6 +40,8 @@ object FirJvmErrors { val INAPPLICABLE_JVM_NAME by error0() val ILLEGAL_JVM_NAME by error0() val FUNCTION_DELEGATE_MEMBER_NAME_CLASH by error0(SourceElementPositioningStrategies.DECLARATION_NAME) + val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error0() + val JVM_INLINE_WITHOUT_VALUE_CLASS by error0() // Types val JAVA_TYPE_MISMATCH by error2() diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt index 596a410fa6a..5b9f2751de6 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmDeclarationCheckers.kt @@ -25,12 +25,13 @@ object JvmDeclarationCheckers : DeclarationCheckers() { override val classCheckers: Set get() = setOf( - FirStrictfpApplicabilityChecker, + FirStrictfpApplicabilityChecker ) override val regularClassCheckers: Set get() = setOf( FirJvmRecordChecker, + FirJvmInlineApplicabilityChecker ) override val propertyCheckers: Set 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 new file mode 100644 index 00000000000..6fc6ef41f1f --- /dev/null +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmInlineApplicabilityChecker.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2021 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.fir.analysis.jvm.checkers.declaration + +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirRegularClassChecker +import org.jetbrains.kotlin.fir.analysis.checkers.getModifier +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.declarations.utils.isExpect +import org.jetbrains.kotlin.fir.declarations.utils.isInline +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_CLASS_ID + +object FirJvmInlineApplicabilityChecker : FirRegularClassChecker() { + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + val annotation = declaration.getAnnotationByClassId(JVM_INLINE_ANNOTATION_CLASS_ID) + if (annotation != null && !declaration.isInline) { + reporter.reportOn(annotation.source, FirJvmErrors.JVM_INLINE_WITHOUT_VALUE_CLASS, context) + } else if (annotation == null && declaration.isInline && !declaration.isExpect) { + reporter.reportOn( + declaration.getModifier(KtTokens.VALUE_KEYWORD)?.source, + FirJvmErrors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, + context + ) + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt index a1473ed14fd..c6687b22a84 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/diagnostics/FirJvmDefaultErrorMessages.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAUL import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_NOT_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_REQUIRED_FOR_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_THROUGH_INHERITANCE +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_INLINE_WITHOUT_VALUE_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES @@ -79,6 +80,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_INLINE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_DELEGATE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_VALUE @@ -163,6 +165,9 @@ object FirJvmDefaultErrorMessages { map.put(FUNCTION_DELEGATE_MEMBER_NAME_CLASH, "Spread operator is prohibited for arguments to signature-polymorphic calls") + map.put(VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, "Value classes without @JvmInline annotation are not supported yet") + map.put(JVM_INLINE_WITHOUT_VALUE_CLASS, "@JvmInline annotation is only applicable to value classes") + map.put(JVM_DEFAULT_NOT_IN_INTERFACE, "'@JvmDefault' is only supported on interface members") map.put( JVM_DEFAULT_IN_JVM6_TARGET, diff --git a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.fir.kt b/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.fir.kt deleted file mode 100644 index 9ff94d33573..00000000000 --- a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.fir.kt +++ /dev/null @@ -1,14 +0,0 @@ -// !SKIP_JAVAC -// !LANGUAGE: +InlineClasses - -package kotlin.jvm - -annotation class JvmInline - -@JvmInline -value class Foo(val x: Int) - -value interface InlineInterface -value annotation class InlineAnn -value object InlineObject -value enum class InlineEnum diff --git a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.kt b/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.kt index 577f3415aac..1f69c45cf88 100644 --- a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.kt +++ b/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclaration.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !SKIP_JAVAC // !LANGUAGE: +InlineClasses diff --git a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.fir.kt b/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.fir.kt deleted file mode 100644 index fe996e295ec..00000000000 --- a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -// !SKIP_JAVAC -// !API_VERSION: 1.4 -// !LANGUAGE: -InlineClasses -// !DIAGNOSTICS: -UNUSED_PARAMETER - -package kotlin.jvm - -annotation class JvmInline - -value class Foo(val x: Int) - -value annotation class InlineAnn -value object InlineObject -value enum class InlineEnum - -@JvmInline -value class NotVal(x: Int) diff --git a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.kt b/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.kt index 553616f7713..9d396da1078 100644 --- a/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.kt +++ b/compiler/testData/diagnostics/tests/valueClasses/basicValueClassDeclarationDisabled.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !SKIP_JAVAC // !API_VERSION: 1.4 // !LANGUAGE: -InlineClasses diff --git a/compiler/testData/diagnostics/tests/valueClasses/jvmInlineApplicability.fir.kt b/compiler/testData/diagnostics/tests/valueClasses/jvmInlineApplicability.fir.kt index 216b252f025..63f795257db 100644 --- a/compiler/testData/diagnostics/tests/valueClasses/jvmInlineApplicability.fir.kt +++ b/compiler/testData/diagnostics/tests/valueClasses/jvmInlineApplicability.fir.kt @@ -11,14 +11,14 @@ inline class IC(val a: Any) @JvmInline value class VC(val a: Any) -@JvmInline +@JvmInline class C -@JvmInline +@JvmInline interface I -@JvmInline +@JvmInline object O -@JvmInline +@JvmInline data class DC(val a: Any) diff --git a/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.fir.kt b/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.fir.kt index 5b20950d9f5..d084e1cd00f 100644 --- a/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.fir.kt +++ b/compiler/testData/diagnostics/tests/valueClasses/valueClassDeclarationCheck.fir.kt @@ -45,8 +45,8 @@ object B2 { @JvmInline final value class D0(val x: Int) -open value class D1(val x: Int) -abstract value class D2(val x: Int) -sealed value class D3(val x: Int) +open value class D1(val x: Int) +abstract value class D2(val x: Int) +sealed value class D3(val x: Int) -value data class D4(val x: String) +value data class D4(val x: String) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt index dcfd76adbb0..3c9075b94e4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt @@ -6,11 +6,13 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.utils.addToStdlib.safeAs val JVM_INLINE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmInline") +val JVM_INLINE_ANNOTATION_CLASS_ID = ClassId.topLevel(JVM_INLINE_ANNOTATION_FQ_NAME) // FIXME: DeserializedClassDescriptor in reflection do not have @JvmInline annotation, that we // FIXME: would like to check as well. diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 334f28ffbfd..786e58f6bb8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -3632,6 +3632,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION) { firDiagnostic -> + ValueClassWithoutJvmInlineAnnotationImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirJvmErrors.JVM_INLINE_WITHOUT_VALUE_CLASS) { firDiagnostic -> + JvmInlineWithoutValueClassImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirJvmErrors.JAVA_TYPE_MISMATCH) { firDiagnostic -> JavaTypeMismatchImpl( firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index b05a8e6d908..1e2b9cf44f8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2529,6 +2529,14 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = FunctionDelegateMemberNameClash::class } + abstract class ValueClassWithoutJvmInlineAnnotation : KtFirDiagnostic() { + override val diagnosticClass get() = ValueClassWithoutJvmInlineAnnotation::class + } + + abstract class JvmInlineWithoutValueClass : KtFirDiagnostic() { + override val diagnosticClass get() = JvmInlineWithoutValueClass::class + } + abstract class JavaTypeMismatch : KtFirDiagnostic() { override val diagnosticClass get() = JavaTypeMismatch::class abstract val expectedType: KtType diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 9f7dc9f7a9a..55c0cb6f8cf 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -4102,6 +4102,20 @@ internal class FunctionDelegateMemberNameClashImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class ValueClassWithoutJvmInlineAnnotationImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ValueClassWithoutJvmInlineAnnotation(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class JvmInlineWithoutValueClassImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.JvmInlineWithoutValueClass(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class JavaTypeMismatchImpl( override val expectedType: KtType, override val actualType: KtType,