[FIR] Add JVM_INLINE_WITHOUT_VALUE_CLASS, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION

This commit is contained in:
Ivan Kochurkin
2021-09-10 19:52:36 +03:00
committed by teamcityserver
parent 7e7066d75e
commit a816bd9a33
18 changed files with 97 additions and 45 deletions
@@ -1,4 +1,4 @@
<!ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_INLINE_CLASS!>value<!> class WithoutConstructor {}
<!ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_INLINE_CLASS, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class WithoutConstructor {}
inline class WithoutParameter<!INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE!>()<!> {}
inline class WithTwoParameters<!INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE!>(val x: Int, val y: String)<!> {}
@@ -3,14 +3,14 @@ class A {
fun foo() {
<!INLINE_CLASS_NOT_TOP_LEVEL, WRONG_MODIFIER_TARGET!>inline<!> class C(val x: Int)
}
inner <!INLINE_CLASS_NOT_TOP_LEVEL!>value<!> class D(val x: Int)
inner <!INLINE_CLASS_NOT_TOP_LEVEL, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D(val x: Int)
}
<!INLINE_CLASS_NOT_FINAL!>open<!> inline class NotFinalClass1(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>abstract<!> inline class NotFinalClass2(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>sealed<!> inline class NotFinalClass3(val x: Int)
<!VALUE_CLASS_CANNOT_BE_CLONEABLE!>value<!> class CloneableClass1(val x: Int): Cloneable
<!VALUE_CLASS_CANNOT_BE_CLONEABLE, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class CloneableClass1(val x: Int): Cloneable
<!VALUE_CLASS_CANNOT_BE_CLONEABLE!>inline<!> class CloneableClass2(val x: Int): java.lang.Cloneable
open class Test
@@ -1,4 +1,4 @@
value class BackingFields(val x: Int) {
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class BackingFields(val x: Int) {
<!PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS!>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_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class WithInner(val x: String) {
<!INNER_CLASS_INSIDE_INLINE_CLASS!>inner<!> class Inner
}
@@ -37,6 +37,9 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val ILLEGAL_JVM_NAME by error<PsiElement>()
val FUNCTION_DELEGATE_MEMBER_NAME_CLASH by error<PsiElement>(PositioningStrategy.DECLARATION_NAME)
val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error<PsiElement>()
val JVM_INLINE_WITHOUT_VALUE_CLASS by error<PsiElement>()
}
val TYPES by object : DiagnosticGroup("Types") {
@@ -40,6 +40,8 @@ object FirJvmErrors {
val INAPPLICABLE_JVM_NAME by error0<PsiElement>()
val ILLEGAL_JVM_NAME by error0<PsiElement>()
val FUNCTION_DELEGATE_MEMBER_NAME_CLASH by error0<PsiElement>(SourceElementPositioningStrategies.DECLARATION_NAME)
val VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION by error0<PsiElement>()
val JVM_INLINE_WITHOUT_VALUE_CLASS by error0<PsiElement>()
// Types
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
@@ -25,12 +25,13 @@ object JvmDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker>
get() = setOf(
FirStrictfpApplicabilityChecker,
FirStrictfpApplicabilityChecker
)
override val regularClassCheckers: Set<FirRegularClassChecker>
get() = setOf(
FirJvmRecordChecker,
FirJvmInlineApplicabilityChecker
)
override val propertyCheckers: Set<FirPropertyChecker>
@@ -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
)
}
}
}
@@ -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,
@@ -1,14 +0,0 @@
// !SKIP_JAVAC
// !LANGUAGE: +InlineClasses
package kotlin.jvm
annotation class JvmInline
@JvmInline
value class Foo(val x: Int)
<!WRONG_MODIFIER_TARGET!>value<!> interface InlineInterface
<!WRONG_MODIFIER_TARGET!>value<!> annotation class InlineAnn
<!WRONG_MODIFIER_TARGET!>value<!> object InlineObject
<!WRONG_MODIFIER_TARGET!>value<!> enum class InlineEnum
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !SKIP_JAVAC
// !LANGUAGE: +InlineClasses
@@ -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)
<!WRONG_MODIFIER_TARGET!>value<!> annotation class InlineAnn
<!WRONG_MODIFIER_TARGET!>value<!> object InlineObject
<!WRONG_MODIFIER_TARGET!>value<!> enum class InlineEnum
@JvmInline
value class NotVal(<!INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER!>x: Int<!>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !SKIP_JAVAC
// !API_VERSION: 1.4
// !LANGUAGE: -InlineClasses
@@ -11,14 +11,14 @@ inline class IC(val a: Any)
@JvmInline
value class VC(val a: Any)
@JvmInline
<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
class C
@JvmInline
<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
interface I
@JvmInline
<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
object O
@JvmInline
<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
data class DC(val a: Any)
@@ -45,8 +45,8 @@ object B2 {
@JvmInline
final value class D0(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>open<!> value class D1(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>abstract<!> value class D2(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>sealed<!> value class D3(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>open<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D1(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>abstract<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D2(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>sealed<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D3(val x: Int)
<!INCOMPATIBLE_MODIFIERS!>value<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class D4(val x: String)
<!INCOMPATIBLE_MODIFIERS, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class D4(val x: String)
@@ -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.
@@ -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),
@@ -2529,6 +2529,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = FunctionDelegateMemberNameClash::class
}
abstract class ValueClassWithoutJvmInlineAnnotation : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ValueClassWithoutJvmInlineAnnotation::class
}
abstract class JvmInlineWithoutValueClass : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = JvmInlineWithoutValueClass::class
}
abstract class JavaTypeMismatch : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = JavaTypeMismatch::class
abstract val expectedType: KtType
@@ -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<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class JvmInlineWithoutValueClassImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.JvmInlineWithoutValueClass(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class JavaTypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,