diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt index e5e7cd76a12..f8556cabd5b 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.caches.createCache import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.caches.getValue import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin +import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.isNewPlaceForBodyGeneration import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider @@ -322,6 +323,25 @@ abstract class AbstractFirDeserializedSymbolProvider( } override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { - return getClass(classId) ?: getTypeAlias(classId) + /** + * FIR has a contract that providers should return the first classifier with required classId they found. + * + * But on the other hand, there is a contract (from pre 1.0 times), that classes have more priority than typealiases, + * when search is performed in binary dependencies. + * + * And the second contract breaks the first in case, when there are two parts of a MPP library: + * - one is platform one and contains `actual typealias` + * - second is common one and contains `expect class` + * + * In this case, by the first contract, provider will return `expect class`, but FIR expects that `actual typealias` will be found + * So, to avoid this problem, we need to search for typealias in case, when `expect class` was found + * + * For details see KT-65840 + */ + val clazz = getClass(classId) + if (clazz != null && !clazz.isExpect) { + return clazz + } + return getTypeAlias(classId) ?: clazz } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt index 411289ed43e..e3253d34fbe 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2Tests.kt @@ -220,6 +220,16 @@ class CustomK2Tests : KGPBaseTest() { } } } + + @GradleTest + @DisplayName("Native metadata compilation against other klib (KT-65840)") + fun nativeMetadataCompilationWithAgainstOtherKlib(gradleVersion: GradleVersion) { + project("k2-common-native-against-other-klib", gradleVersion) { + build(":app:compileNativeMainKotlinMetadata") { + assertTasksExecuted(":app:compileNativeMainKotlinMetadata") + } + } + } } @NativeGradlePluginTests diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/app/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/app/build.gradle.kts new file mode 100644 index 00000000000..6b9d089fb6f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/app/build.gradle.kts @@ -0,0 +1,7 @@ +kotlin { + sourceSets { + commonMain.dependencies { + implementation(project(":lib")) + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/app/src/nativeMain/kotlin/Main.native.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/app/src/nativeMain/kotlin/Main.native.kt new file mode 100644 index 00000000000..3d51f60ef9d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/app/src/nativeMain/kotlin/Main.native.kt @@ -0,0 +1,3 @@ +fun test() { + val s: Some = createSome() +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/build.gradle.kts new file mode 100644 index 00000000000..8e7d08b3fcd --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/build.gradle.kts @@ -0,0 +1,37 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask + +group = "test" +version = "1.0" + +plugins { + kotlin("multiplatform") +} + +repositories { + mavenLocal() + mavenCentral() +} + +subprojects { + apply { + plugin("kotlin-multiplatform") + } + + kotlin { + applyDefaultHierarchyTemplate() + linuxX64() + macosX64() + } + + repositories { + mavenLocal() + mavenCentral() + } + + tasks.withType>().configureEach { + compilerOptions { + freeCompilerArgs.add("-Xrender-internal-diagnostic-names") + } + } +} + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/build.gradle.kts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/src/commonMain/kotlin/Lib.common.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/src/commonMain/kotlin/Lib.common.kt new file mode 100644 index 00000000000..ce7ed48d182 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/src/commonMain/kotlin/Lib.common.kt @@ -0,0 +1,3 @@ +expect class Some { + fun foo() +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/src/nativeMain/kotlin/Main.native.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/src/nativeMain/kotlin/Main.native.kt new file mode 100644 index 00000000000..c9dc4d9f7ae --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/lib/src/nativeMain/kotlin/Main.native.kt @@ -0,0 +1,7 @@ +class Other { + fun foo() {} +} + +actual typealias Some = Other + +fun createSome(): Some = Other() diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/settings.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/settings.gradle.kts new file mode 100644 index 00000000000..d7baa552eee --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/k2-common-native-against-other-klib/settings.gradle.kts @@ -0,0 +1 @@ +include(":app", ":lib")