diff --git a/compiler/testData/codegen/box/cinterop/kt59167.kt b/compiler/testData/codegen/box/cinterop/kt59167.kt new file mode 100644 index 00000000000..e69af11b5e3 --- /dev/null +++ b/compiler/testData/codegen/box/cinterop/kt59167.kt @@ -0,0 +1,30 @@ +/* +* Copyright 2010-2023 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. +*/ +// TARGET_BACKEND: NATIVE +// DISABLE_NATIVE: isAppleTarget=false +// There is no GameController on watchOS. +// DISABLE_NATIVE: targetFamily=WATCHOS +// MODULE: cinterop +// FILE: kt59167.def +language=Objective-C +--- +#import + +// We only need to touch the problematic header to trigger the problem, +// so actual code does not matter. +id dummy() { + return nil; +} + +// MODULE: main(cinterop) +// FILE: main.kt +@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class) +import kotlin.test.* +import kt59167.* + +fun box(): String { + assertNull(dummy()) + return "OK" +} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 7b5d801a60c..2a61a2866b4 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -1231,9 +1231,6 @@ if (PlatformInfo.isAppleTarget(project)) { it.defFile 'interop/objc/objCAction/objclib.def' it.headers "$projectDir/interop/objc/objCAction/objclib.h" } - createInterop("kt59167") { - it.defFile 'interop/kt59167/kt59167.def' - } createInterop("overridabilityCondition") { it.defFile 'interop/objc/overridabilityCondition/lib.def' it.headers "$projectDir/interop/objc/overridabilityCondition/lib.h" @@ -1850,13 +1847,6 @@ if (PlatformInfo.isAppleTarget(project)) { UtilsKt.dependsOnPlatformLibs(it) } - interopTest("interop_kt59167") { - // There is no GameController on watchOS. - enabled = target.family != Family.WATCHOS - source = 'interop/kt59167/main.kt' - interop = 'kt59167' - } - interopTest("interop_objc_kt63423_dispose_on_main_stress") { // Test depends on macOS-specific AppKit enabled = (project.testTarget == 'macos_x64' || project.testTarget == 'macos_arm64' || project.testTarget == null) diff --git a/kotlin-native/backend.native/tests/interop/kt59167/kt59167.def b/kotlin-native/backend.native/tests/interop/kt59167/kt59167.def deleted file mode 100644 index 8678caca6d7..00000000000 --- a/kotlin-native/backend.native/tests/interop/kt59167/kt59167.def +++ /dev/null @@ -1,9 +0,0 @@ -language=Objective-C ---- -#import - -// We only need to touch the problematic header to trigger the problem, -// so actual code does not matter. -id dummy() { - return nil; -} \ No newline at end of file diff --git a/kotlin-native/backend.native/tests/interop/kt59167/main.kt b/kotlin-native/backend.native/tests/interop/kt59167/main.kt deleted file mode 100644 index 86480bb67b2..00000000000 --- a/kotlin-native/backend.native/tests/interop/kt59167/main.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2010-2023 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. - */ - -import kotlin.test.* -import kt59167.* - -fun main() { - assertNull(dummy()) -} \ No newline at end of file diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestGenerated.java index b71f80590e9..0f71e38f7c8 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestGenerated.java @@ -4856,6 +4856,12 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe runTest("compiler/testData/codegen/box/cinterop/kt57640.kt"); } + @Test + @TestMetadata("kt59167.kt") + public void testKt59167() throws Exception { + runTest("compiler/testData/codegen/box/cinterop/kt59167.kt"); + } + @Test @TestMetadata("kt63048.kt") public void testKt63048() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestNoPLGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestNoPLGenerated.java index 67572492085..bd710e901ca 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestNoPLGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/FirNativeCodegenBoxTestNoPLGenerated.java @@ -4966,6 +4966,12 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB runTest("compiler/testData/codegen/box/cinterop/kt57640.kt"); } + @Test + @TestMetadata("kt59167.kt") + public void testKt59167() throws Exception { + runTest("compiler/testData/codegen/box/cinterop/kt59167.kt"); + } + @Test @TestMetadata("kt63048.kt") public void testKt63048() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestGenerated.java index a0387a4996a..fed29c2d7a9 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestGenerated.java @@ -4746,6 +4746,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest runTest("compiler/testData/codegen/box/cinterop/kt57640.kt"); } + @Test + @TestMetadata("kt59167.kt") + public void testKt59167() throws Exception { + runTest("compiler/testData/codegen/box/cinterop/kt59167.kt"); + } + @Test @TestMetadata("kt63048.kt") public void testKt63048() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestNoPLGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestNoPLGenerated.java index 87f725b2d86..601cc189506 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestNoPLGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/test/blackbox/NativeCodegenBoxTestNoPLGenerated.java @@ -4857,6 +4857,12 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT runTest("compiler/testData/codegen/box/cinterop/kt57640.kt"); } + @Test + @TestMetadata("kt59167.kt") + public void testKt59167() throws Exception { + runTest("compiler/testData/codegen/box/cinterop/kt59167.kt"); + } + @Test @TestMetadata("kt63048.kt") public void testKt63048() throws Exception { diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationResult.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationResult.kt index e5c1e566162..73a29dee9ba 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationResult.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilationResult.kt @@ -29,7 +29,7 @@ internal sealed interface TestCompilationResult { companion object { fun TestCompilationResult.assertSuccess(): Success = when (this) { is Success -> this - is UnexpectedFailure -> fail { describeFailure() } + is UnexpectedFailure -> throw CompilationToolException(describeFailure()) is CompilationToolFailure -> throw CompilationToolException(describeFailure()) is DependencyFailures -> fail { describeDependencyFailures() } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ConditionallyDisabledTests.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ConditionallyDisabledTests.kt index 3ce3e891680..20c25faceb5 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ConditionallyDisabledTests.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ConditionallyDisabledTests.kt @@ -7,9 +7,9 @@ package org.jetbrains.kotlin.konan.test.blackbox.support.group import org.jetbrains.kotlin.konan.test.blackbox.support.ClassLevelProperty // Deprecated: Use test directives instead: -// `IGNORE_BACKEND: NATIVE`, `IGNORE_BACKEND_K1: NATIVE`, `IGNORE_BACKEND_K2: NATIVE` if test fails in any tets config -// `IGNORE_NATIVE`, `IGNORE_NATIVE_K1`, `IGNORE_NATIVE_K2` with a property matcher, for usual easy fails -// `DISABLE_NATIVE`, `DISABLE_NATIVE_K1`, `DISABLE_NATIVE_K2` in case compiler crashes within JVM +// `IGNORE_BACKEND: NATIVE`, `IGNORE_BACKEND_K1: NATIVE`, `IGNORE_BACKEND_K2: NATIVE` if test fails in any test config +// `IGNORE_NATIVE`, `IGNORE_NATIVE_K1`, `IGNORE_NATIVE_K2` with/without a property matcher, for usual easy fails (please provide issue link) +// `DISABLE_NATIVE`, `DISABLE_NATIVE_K1`, `DISABLE_NATIVE_K2` with/without a property matcher, in case compiler crashes within JVM, or compilation/execution would be a resource waste @Target(AnnotationTarget.CLASS) internal annotation class DisabledTests( val sourceLocations: Array @@ -17,8 +17,8 @@ internal annotation class DisabledTests( // @DisabledTestsIfProperty(...) is intended primarily to turn off tests in bulk to reduce pressure on CI infrastructure for certain targets // To mark failed tests, please use the following test directives instead: -// `IGNORE_NATIVE`, `IGNORE_NATIVE_K1`, `IGNORE_NATIVE_K2` with a property matcher, for usual easy fails -// `DISABLE_NATIVE`, `DISABLE_NATIVE_K1`, `DISABLE_NATIVE_K2` for overcomplicated property combinations, or in case compiler crashes within JVM +// `IGNORE_NATIVE`, `IGNORE_NATIVE_K1`, `IGNORE_NATIVE_K2` with/without a property matcher, for usual easy fails (please provide issue link) +// `DISABLE_NATIVE`, `DISABLE_NATIVE_K1`, `DISABLE_NATIVE_K2` with/without a property matcher, in case compiler crashes within JVM, or compilation/execution would be a resource waste @Target(AnnotationTarget.CLASS) internal annotation class DisabledTestsIfProperty( val sourceLocations: Array, diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt index 2477a54d6a8..c457b9d7f4d 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.konan.test.blackbox.support.* import org.jetbrains.kotlin.konan.test.blackbox.support.TestCase.WithTestRunnerExtras import org.jetbrains.kotlin.konan.test.blackbox.support.TestDirectives.ASSERTIONS_MODE @@ -47,6 +48,7 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils.* import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_K1 import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_K2 +import org.jetbrains.kotlin.test.directives.model.StringDirective import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.utils.addIfNotNull @@ -155,7 +157,7 @@ private class ExtTestDataFile( val isRelevant: Boolean = isCompatibleTarget(TargetBackend.NATIVE, testDataFile) // Checks TARGET_BACKEND/DONT_TARGET_EXACT_BACKEND directives. - && !isDisabledNative(pipelineType, structure.directives) + && !settings.isDisabledNative(structure.directives) && testDataFileSettings.languageSettings.none { it in INCOMPATIBLE_LANGUAGE_SETTINGS } && INCOMPATIBLE_DIRECTIVES.none { it in structure.directives } && structure.directives[API_VERSION_DIRECTIVE] !in INCOMPATIBLE_API_VERSIONS @@ -893,14 +895,6 @@ private class ExtTestDataFileStructureFactory(parentDisposable: Disposable) : Te } } -internal fun isDisabledNative(pipelineType: PipelineType, directives: Directives): Boolean { - return when (pipelineType) { - PipelineType.K1 -> directives.contains(DISABLE_NATIVE.name) || directives.contains(DISABLE_NATIVE_K1.name) - PipelineType.K2 -> directives.contains(DISABLE_NATIVE.name) || directives.contains(DISABLE_NATIVE_K2.name) - PipelineType.DEFAULT -> directives.contains(DISABLE_NATIVE.name) - } -} - internal fun Settings.isIgnoredTarget(testDataFile: File): Boolean { val disposable = Disposer.newDisposable("Disposable for ExtTestCaseGroupProvider.isIgnoredTarget") try { @@ -934,24 +928,27 @@ private fun Settings.isIgnoredWithIGNORE_BACKEND(directives: Directives): Boolea return false } +private val TARGET_FAMILY = "targetFamily" +private val IS_APPLE_TARGET = "isAppleTarget" private val CACHE_MODE_NAMES = CacheMode.Alias.entries.map { it.name } private val TEST_MODE_NAMES = TestMode.entries.map { it.name } private val OPTIMIZATION_MODE_NAMES = OptimizationMode.entries.map { it.name } private val GC_TYPE_NAMES = GCType.entries.map { it.name } +private val FAMILY_NAMES = Family.entries.map { it.name } +private val BOOLEAN_NAMES = listOf(true.toString(), false.toString()) -private fun Settings.isIgnoredWithIGNORE_NATIVE( - directives: Directives, -): Boolean { - val directiveValues = buildList { - directives.listValues(IGNORE_NATIVE.name)?.let { addAll(it) } - when (get()) { - PipelineType.K1 -> directives.listValues(IGNORE_NATIVE_K1.name)?.let { addAll(it) } - PipelineType.K2 -> directives.listValues(IGNORE_NATIVE_K2.name)?.let { addAll(it) } - else -> {} - } - } - // Boolean evaluation of expressions like `property1=value1 && property2=value2` +private fun Settings.isDisabledNative(directives: Directives) = + evaluate(getDirectiveValues(directives, DISABLE_NATIVE, DISABLE_NATIVE_K1, DISABLE_NATIVE_K2)) + +private fun Settings.isIgnoredWithIGNORE_NATIVE(directives: Directives) = + evaluate(getDirectiveValues(directives, IGNORE_NATIVE, IGNORE_NATIVE_K1, IGNORE_NATIVE_K2)) + +// Evaluation of conjunction of boolean expressions like `property1=value1 && property2=value2`. +// Any null element makes whole result as `true`. +private fun Settings.evaluate(directiveValues: List): Boolean { directiveValues.forEach { + if (it == null) + return true // Directive without value is treated as unconditional val split = it.split("&&") val booleanList = split.map { val matchResult = "(.+)=(.+)".toRegex().find(it.trim()) @@ -963,6 +960,8 @@ private fun Settings.isIgnoredWithIGNORE_NATIVE( ClassLevelProperty.OPTIMIZATION_MODE.shortName -> get().name to OPTIMIZATION_MODE_NAMES ClassLevelProperty.TEST_TARGET.shortName -> get().testTarget.name to null ClassLevelProperty.GC_TYPE.shortName -> get().name to GC_TYPE_NAMES + TARGET_FAMILY -> get().testTarget.family.name to FAMILY_NAMES + IS_APPLE_TARGET -> get().testTarget.family.isAppleFamily.toString() to BOOLEAN_NAMES else -> throw AssertionError("ClassLevelProperty name: $propName is not yet supported in IGNORE_NATIVE* test directives.") } val valueFromTestDirective = matchResult.groups[2]?.value!! @@ -981,6 +980,26 @@ private fun Settings.isIgnoredWithIGNORE_NATIVE( return false } +// Returns list of relevant directive values. +// Null is added to result list in case the directive given without value. +private fun Settings.getDirectiveValues( + directives: Directives, + directiveAllPipelineTypes: StringDirective, + directiveK1: StringDirective, + directiveK2: StringDirective +): List = buildList { + fun extract(directives: Directives, directive: StringDirective) { + if (directives.contains(directive.name)) + directives.listValues(directive.name)?.let { addAll(it) } ?: add(null) + } + extract(directives, directiveAllPipelineTypes) + when (get()) { + PipelineType.K1 -> extract(directives, directiveK1) + PipelineType.K2 -> extract(directives, directiveK2) + else -> {} + } +} + private val KtFile.packageFqNameForKLib: FqName get() = when (name.substringAfterLast(".")) { "kt" -> packageFqName