Fix checker for -Xjvm-defaults
This commit is contained in:
+11
-7
@@ -28,33 +28,37 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.util.getNonPrivateTraitMembersForDelegation
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : DeclarationChecker {
|
||||
class JvmDefaultChecker(private val jvmTarget: JvmTarget, private val project: Project) : DeclarationChecker {
|
||||
|
||||
private val ideService = LanguageVersionSettingsProvider.getInstance(project)
|
||||
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
val jvmDefaultMode = context.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode)
|
||||
|
||||
descriptor.annotations.findAnnotation(JVM_DEFAULT_FQ_NAME)?.let { annotationDescriptor ->
|
||||
val jvmDefaultAnnotation = descriptor.annotations.findAnnotation(JVM_DEFAULT_FQ_NAME)
|
||||
jvmDefaultAnnotation?.let { annotationDescriptor ->
|
||||
val reportOn = DescriptorToSourceUtils.getSourceFromAnnotation(annotationDescriptor) ?: declaration
|
||||
if (!isInterface(descriptor.containingDeclaration)) {
|
||||
context.trace.report(ErrorsJvm.JVM_DEFAULT_NOT_IN_INTERFACE.on(reportOn))
|
||||
return@check
|
||||
} else if (jvmTarget == JvmTarget.JVM_1_6) {
|
||||
context.trace.report(ErrorsJvm.JVM_DEFAULT_IN_JVM6_TARGET.on(reportOn, "JvmDefault"))
|
||||
return@check
|
||||
} else if (!jvmDefaultMode.isEnabled) {
|
||||
context.trace.report(ErrorsJvm.JVM_DEFAULT_IN_DECLARATION.on(declaration, "JvmDefault"))
|
||||
return@check
|
||||
}
|
||||
return@check
|
||||
}
|
||||
|
||||
descriptor.annotations.findAnnotation(JVM_DEFAULT_NO_COMPATIBILITY_FQ_NAME)?.let { annotationDescriptor ->
|
||||
val reportOn = DescriptorToSourceUtils.getSourceFromAnnotation(annotationDescriptor) ?: declaration
|
||||
if (jvmTarget == JvmTarget.JVM_1_6) {
|
||||
context.trace.report(ErrorsJvm.JVM_DEFAULT_IN_JVM6_TARGET.on(reportOn, "JvmDefaultWithoutCompatibility"))
|
||||
return@check
|
||||
} else if (!jvmDefaultMode.isEnabled) {
|
||||
context.trace.report(ErrorsJvm.JVM_DEFAULT_IN_DECLARATION.on(reportOn, "JvmDefaultWithoutCompatibility"))
|
||||
return@check
|
||||
}
|
||||
return@check
|
||||
}
|
||||
|
||||
if (descriptor is ClassDescriptor) {
|
||||
@@ -68,7 +72,7 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : Declaratio
|
||||
}
|
||||
|
||||
|
||||
if (!jvmDefaultMode.forAllMethodsWithBody && isInterface(descriptor.containingDeclaration)) {
|
||||
if (jvmDefaultAnnotation == null && !jvmDefaultMode.forAllMethodsWithBody && isInterface(descriptor.containingDeclaration)) {
|
||||
val memberDescriptor = descriptor as? CallableMemberDescriptor ?: return
|
||||
if (descriptor is PropertyAccessorDescriptor) return
|
||||
|
||||
@@ -87,7 +91,7 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : Declaratio
|
||||
|
||||
if (!jvmDefaultMode.isEnabled || descriptor !is ClassDescriptor || isInterface(descriptor) || isAnnotationClass(descriptor)) return
|
||||
// JvmDefaults members checks across class hierarchy:
|
||||
// 1. If in old scheme class have implicit override with different signature than overriden method (e.g. generic specialization)
|
||||
// 1. If in old scheme class have implicit override with different signature than overridden method (e.g. generic specialization)
|
||||
// report error because absent of it's can affect library ABI
|
||||
// 2. If it's mixed hierarchy with implicit override in base class and override one in inherited derived interface report error.
|
||||
// Otherwise the implicit class override would be used for dispatching method calls (but not more specialized)
|
||||
@@ -225,7 +229,7 @@ class JvmDefaultChecker(val jvmTarget: JvmTarget, project: Project) : Declaratio
|
||||
|
||||
private fun CallableMemberDescriptor.isCompiledToJvmDefaultWithProperMode(compilationDefaultMode: JvmDefaultMode): Boolean {
|
||||
val jvmDefault =
|
||||
if (this is DeserializedDescriptor) compilationDefaultMode else ideService?.getModuleLanguageVersionSettings(module)
|
||||
if (this is DeserializedDescriptor) compilationDefaultMode/*doesn't matter*/ else ideService?.getModuleLanguageVersionSettings(module)
|
||||
?.getFlag(JvmAnalysisFlags.jvmDefaultMode) ?: compilationDefaultMode
|
||||
return isCompiledToJvmDefault(jvmDefault)
|
||||
}
|
||||
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/jvmDefaultClashWithNoCompatibility/library/a.kt
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
package base
|
||||
|
||||
interface UExpression {
|
||||
fun evaluate(): Any? = "fail"
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/jvmDefaultClashWithNoCompatibility/source.kt:12:7: error: explicit override is required for 'public open fun evaluate(): Any? defined in KotlinUBinaryExpressionWithType' in the '-Xjvm-default=all-compatibility' mode. Otherwise, implicit class override 'public open fun evaluate(): Any? defined in KotlinAbstractUExpression' (compiled in the old -Xjvm-default mode) is not fully overridden and might be incorrectly called at runtime
|
||||
class KotlinUBinaryExpressionWithType : KotlinAbstractUExpression(), KotlinEvaluatableUElement {}
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
import base.*
|
||||
|
||||
interface KotlinEvaluatableUElement : UExpression {
|
||||
override fun evaluate(): Any? {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KotlinAbstractUExpression() : UExpression {}
|
||||
|
||||
@JvmDefaultWithoutCompatibility
|
||||
class KotlinUBinaryExpressionWithType : KotlinAbstractUExpression(), KotlinEvaluatableUElement {}
|
||||
|
||||
fun box(): String {
|
||||
val foo = KotlinUBinaryExpressionWithType()
|
||||
return foo.evaluate() as String
|
||||
}
|
||||
+5
@@ -593,6 +593,11 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
|
||||
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-jvm-target", "1.8", "-Xjvm-default=all"))
|
||||
}
|
||||
|
||||
fun testJvmDefaultClashWithNoCompatibility() {
|
||||
val library = compileLibrary("library", additionalOptions = listOf("-Xjvm-default=disable"))
|
||||
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-jvm-target", "1.8", "-Xjvm-default=all-compatibility"))
|
||||
}
|
||||
|
||||
fun testJvmDefaultCompatibilityAgainstJava() {
|
||||
val library = compileLibrary("library", additionalOptions = listOf("-Xjvm-default=disable"))
|
||||
compileKotlin(
|
||||
|
||||
Reference in New Issue
Block a user