diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 7b45369a998..6a98bc36993 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -4110,6 +4110,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION) { firDiagnostic -> + JvmDefaultWithCompatibilityInDeclarationImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } + add(FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE) { firDiagnostic -> + JvmDefaultWithCompatibilityNotOnInterfaceImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirJvmErrors.USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL) { firDiagnostic -> UsageOfJvmDefaultThroughSuperCallImpl( firDiagnostic as KtPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index be1c442d15a..798e74b82f6 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -2859,6 +2859,14 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val annotation: String } + abstract class JvmDefaultWithCompatibilityInDeclaration : KtFirDiagnostic() { + override val diagnosticClass get() = JvmDefaultWithCompatibilityInDeclaration::class + } + + abstract class JvmDefaultWithCompatibilityNotOnInterface : KtFirDiagnostic() { + override val diagnosticClass get() = JvmDefaultWithCompatibilityNotOnInterface::class + } + abstract class UsageOfJvmDefaultThroughSuperCall : KtFirDiagnostic() { override val diagnosticClass get() = UsageOfJvmDefaultThroughSuperCall::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 74101bd66b0..f436e229b9b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -3456,6 +3456,16 @@ internal class JvmDefaultInDeclarationImpl( override val token: ValidityToken, ) : KtFirDiagnostic.JvmDefaultInDeclaration(), KtAbstractFirDiagnostic +internal class JvmDefaultWithCompatibilityInDeclarationImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.JvmDefaultWithCompatibilityInDeclaration(), KtAbstractFirDiagnostic + +internal class JvmDefaultWithCompatibilityNotOnInterfaceImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.JvmDefaultWithCompatibilityNotOnInterface(), KtAbstractFirDiagnostic + internal class UsageOfJvmDefaultThroughSuperCallImpl( override val firDiagnostic: KtPsiDiagnostic, override val token: ValidityToken, 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 9de24a8e992..56767e31b93 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 @@ -112,6 +112,8 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { val JVM_DEFAULT_IN_DECLARATION by error(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) { parameter("annotation") } + val JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION by error() + val JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE by error() val USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL by error() val NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT by warning(PositioningStrategy.DECLARATION_SIGNATURE) } 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 0bd7e625e1f..58f859d62d5 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 @@ -93,6 +93,8 @@ object FirJvmErrors { val JVM_DEFAULT_IN_JVM6_TARGET by error1() val JVM_DEFAULT_REQUIRED_FOR_OVERRIDE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val JVM_DEFAULT_IN_DECLARATION by error1(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) + val JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION by error0() + val JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE by error0() val USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL by error0() val NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT by warning0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt index 5ab5586266b..b62ba94a49f 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt @@ -36,6 +36,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAUL import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET 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_WITH_COMPATIBILITY_IN_DECLARATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE 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 @@ -176,6 +178,14 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() { ) map.put(JVM_DEFAULT_REQUIRED_FOR_OVERRIDE, "'@JvmDefault' is required for an override of a '@JvmDefault' member") map.put(JVM_DEFAULT_IN_DECLARATION, "Usage of ''@{0}'' is only allowed with -Xjvm-default option", STRING) + map.put( + JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION, + "Usage of '@JvmDefaultWithCompatibility' is only allowed with '-Xjvm-default=all' option" + ) + map.put( + JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE, + "'@JvmDefaultWithCompatibility' annotation is only allowed on interfaces" + ) map.put( USAGE_OF_JVM_DEFAULT_THROUGH_SUPER_CALL, "Super calls of '@JvmDefault' members are only allowed with -Xjvm-default option" diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmDefaultChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmDefaultChecker.kt index 87913d0d980..c8d6b1fc47f 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmDefaultChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirJvmDefaultChecker.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_CLASS_ID import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID +import org.jetbrains.kotlin.name.JvmNames.JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID object FirJvmDefaultChecker : FirBasicDeclarationChecker() { override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { @@ -36,35 +37,67 @@ object FirJvmDefaultChecker : FirBasicDeclarationChecker() { if (defaultAnnotation != null) { val containingDeclaration = context.findClosest() - if (containingDeclaration !is FirClass || !containingDeclaration.isInterface) { - reporter.reportOn(defaultAnnotation.source, FirJvmErrors.JVM_DEFAULT_NOT_IN_INTERFACE, context) - return - } else if (context.isJvm6()) { - reporter.reportOn(defaultAnnotation.source, FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, "JvmDefault", context) - return - } else if (!jvmDefaultMode.isEnabled) { - reporter.reportOn(defaultAnnotation.source, FirJvmErrors.JVM_DEFAULT_IN_DECLARATION, "JvmDefault", context) - return + val source = defaultAnnotation.source + when { + containingDeclaration !is FirClass || !containingDeclaration.isInterface -> { + reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_NOT_IN_INTERFACE, context) + return + } + context.isJvm6() -> { + reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, "JvmDefault", context) + return + } + !jvmDefaultMode.isEnabled -> { + reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_IN_DECLARATION, "JvmDefault", context) + return + } } } else { - val annotation = declaration.getAnnotationByClassId(JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID) - if (annotation != null) { - if (context.isJvm6()) { - reporter.reportOn( - annotation.source, - FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, - "JvmDefaultWithoutCompatibility", - context - ) - return - } else if (!jvmDefaultMode.isEnabled) { - reporter.reportOn( - annotation.source, - FirJvmErrors.JVM_DEFAULT_IN_DECLARATION, - "JvmDefaultWithoutCompatibility", - context - ) - return + val annotationNoCompatibility = declaration.getAnnotationByClassId(JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID) + if (annotationNoCompatibility != null) { + val source = annotationNoCompatibility.source + when { + context.isJvm6() -> { + reporter.reportOn( + source, + FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, + "JvmDefaultWithoutCompatibility", + context + ) + return + } + !jvmDefaultMode.isEnabled -> { + reporter.reportOn( + source, + FirJvmErrors.JVM_DEFAULT_IN_DECLARATION, + "JvmDefaultWithoutCompatibility", + context + ) + return + } + } + } + val annotationWithCompatibility = declaration.getAnnotationByClassId(JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID) + if (annotationWithCompatibility != null) { + val source = annotationWithCompatibility.source + when { + context.isJvm6() -> { + reporter.reportOn( + source, + FirJvmErrors.JVM_DEFAULT_IN_JVM6_TARGET, + "JvmDefaultWithCompatibility", + context + ) + return + } + jvmDefaultMode != JvmDefaultMode.ALL_INCOMPATIBLE -> { + reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_IN_DECLARATION, context) + return + } + declaration !is FirRegularClass || !declaration.isInterface -> { + reporter.reportOn(source, FirJvmErrors.JVM_DEFAULT_WITH_COMPATIBILITY_NOT_ON_INTERFACE, context) + return + } } } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.fir.kt deleted file mode 100644 index c7dc6b0414d..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.fir.kt +++ /dev/null @@ -1,7 +0,0 @@ -// !JVM_TARGET: 1.6 - -@JvmDefaultWithCompatibility -interface A {} - -@JvmDefaultWithCompatibility -class B : A {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.kt index 017c419d506..f28be713b5b 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target6.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !JVM_TARGET: 1.6 @JvmDefaultWithCompatibility diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.fir.kt deleted file mode 100644 index 4e734352f2e..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.fir.kt +++ /dev/null @@ -1,10 +0,0 @@ -// !JVM_TARGET: 1.8 -// !JVM_DEFAULT_MODE: all - -@JvmDefaultWithCompatibility -interface A { - fun test(p: T) {} -} - -@JvmDefaultWithCompatibility -class B : A {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.kt index 80f0b76a1fb..284a8f7c148 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !JVM_TARGET: 1.8 // !JVM_DEFAULT_MODE: all diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.fir.kt deleted file mode 100644 index 13a28c9ccd4..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -// !JVM_TARGET: 1.8 - -@JvmDefaultWithCompatibility -interface A { - fun test(p: T) {} -} - -@JvmDefaultWithCompatibility -class B : A {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.kt index 848ace1713a..5ae0e129928 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/jvmDefaultWithCompatibility/target8Disabled.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !JVM_TARGET: 1.8 @JvmDefaultWithCompatibility diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt index 8ad334d4923..987a789b48a 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/name/JvmNames.kt @@ -21,6 +21,7 @@ object JvmNames { val JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithoutCompatibility") val JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME = FqName("kotlin.jvm.JvmDefaultWithCompatibility") val JVM_DEFAULT_NO_COMPATIBILITY_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME) + val JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME) val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads") val JVM_OVERLOADS_CLASS_ID = ClassId.topLevel(JVM_OVERLOADS_FQ_NAME)