diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.kt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.kt index 16be720839f..02c946a392b 100644 --- a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.kt +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/actual_object.kt @@ -7,7 +7,7 @@ expect object Platform { val name: String } -// MODULE: androidMain(commonMain) +// MODULE: androidMain()()(commonMain) // FILE: JvmAndroid.kt package sample diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/matchingButIncompatibleExpect.kt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/matchingButIncompatibleExpect.kt index ff9f97e426a..f796e206f68 100644 --- a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/matchingButIncompatibleExpect.kt +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/matchingButIncompatibleExpect.kt @@ -6,7 +6,7 @@ package sample expect fun foo() -// MODULE: androidMain(commonMain) +// MODULE: androidMain()()(commonMain) // FILE: JvmAndroid.kt package sample diff --git a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt index 8bb62fbb03d..5710e129b04 100644 --- a/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt +++ b/analysis/analysis-api/testData/components/multiplatformInfoProvider/expectForActual/multipleExpects.kt @@ -12,7 +12,7 @@ expect fun foo() package sample expect fun foo() -// MODULE: androidMain(commonMain1, commonMain2) +// MODULE: androidMain()()(commonMain1, commonMain2) // FILE: JvmAndroid.kt package sample diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.fir.txt index bc13efddc07..71ab100de84 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.fir.txt @@ -26,7 +26,64 @@ FILE: common.kt } } -Module: m1-jvm +FILE: jvm.kt + public open actual class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public open actual fun foo(arg: R|T|): R|kotlin/Unit| { + } + + public open fun bar(arg: R|T|): R|T| { + ^bar R|/arg| + } + + public open fun baz(arg: R|T|): R|T| { + ^baz R|/arg| + } + + } + public final class D : R|C| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|SubstitutionOverride|(String()) + this@R|/D|.R|/C.bar|(String()) + this@R|/D|.R|SubstitutionOverride|(String()) + } + + } +Module: m1-jvm +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public open expect fun foo(arg: R|T|): R|kotlin/Unit| + + } + public open class B : R|A| { + public constructor(): R|B| { + super|>() + } + + } + public open class C : R|B| { + public constructor(): R|C| { + super() + } + + public open fun bar(arg: R|kotlin/String|): R|kotlin/String| { + ^bar R|/arg| + } + + public open fun baz(arg: R|kotlin/CharSequence|): R|kotlin/String| { + ^baz R|/arg|.R|kotlin/Any.toString|() + } + + } FILE: jvm.kt public open actual class A : R|kotlin/Any| { public constructor(): R|A| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.kt index 21388fc95bc..64898561b22 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.kt @@ -10,11 +10,11 @@ open class B : A() { // Fake (JVM only): override fun bar(arg: String): String = super.bar(arg) } open class C : B() { - open fun bar(arg: String): String = arg + open fun bar(arg: String): String = arg open fun baz(arg: CharSequence): String = arg.toString() } -// MODULE: m1-jvm(m1-common) +// MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual open class A { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.fir.txt new file mode 100644 index 00000000000..71ab100de84 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.fir.txt @@ -0,0 +1,116 @@ +Module: m1-common +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public open expect fun foo(arg: R|T|): R|kotlin/Unit| + + } + public open class B : R|A| { + public constructor(): R|B| { + super|>() + } + + } + public open class C : R|B| { + public constructor(): R|C| { + super() + } + + public open fun bar(arg: R|kotlin/String|): R|kotlin/String| { + ^bar R|/arg| + } + + public open fun baz(arg: R|kotlin/CharSequence|): R|kotlin/String| { + ^baz R|/arg|.R|kotlin/Any.toString|() + } + + } +FILE: jvm.kt + public open actual class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public open actual fun foo(arg: R|T|): R|kotlin/Unit| { + } + + public open fun bar(arg: R|T|): R|T| { + ^bar R|/arg| + } + + public open fun baz(arg: R|T|): R|T| { + ^baz R|/arg| + } + + } + public final class D : R|C| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|SubstitutionOverride|(String()) + this@R|/D|.R|/C.bar|(String()) + this@R|/D|.R|SubstitutionOverride|(String()) + } + + } +Module: m1-jvm +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public open expect fun foo(arg: R|T|): R|kotlin/Unit| + + } + public open class B : R|A| { + public constructor(): R|B| { + super|>() + } + + } + public open class C : R|B| { + public constructor(): R|C| { + super() + } + + public open fun bar(arg: R|kotlin/String|): R|kotlin/String| { + ^bar R|/arg| + } + + public open fun baz(arg: R|kotlin/CharSequence|): R|kotlin/String| { + ^baz R|/arg|.R|kotlin/Any.toString|() + } + + } +FILE: jvm.kt + public open actual class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public open actual fun foo(arg: R|T|): R|kotlin/Unit| { + } + + public open fun bar(arg: R|T|): R|T| { + ^bar R|/arg| + } + + public open fun baz(arg: R|T|): R|T| { + ^baz R|/arg| + } + + } + public final class D : R|C| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|SubstitutionOverride|(String()) + this@R|/D|.R|/C.bar|(String()) + this@R|/D|.R|SubstitutionOverride|(String()) + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.kt new file mode 100644 index 00000000000..9380af8ea87 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.kt @@ -0,0 +1,35 @@ +// LL_FIR_DIVERGENCE +// I have no idea why the tests diverge. The test was misconfigured (it used regular dependencies instead of `dependsOn` dependencies). +// I fixed the misconfiguration, now it turns out that it has been diverged all the time +// LL_FIR_DIVERGENCE +// !LANGUAGE: +MultiPlatformProjects +// MODULE: m1-common +// FILE: common.kt + +expect open class A() { + open fun foo(arg: T) +} +open class B : A() { + // Fake: override fun foo(arg: String) = super.foo(arg) + // Fake (JVM only): override fun bar(arg: String): String = super.bar(arg) +} +open class C : B() { + open fun bar(arg: String): String = arg + open fun baz(arg: CharSequence): String = arg.toString() +} + +// MODULE: m1-jvm()()(m1-common) +// FILE: jvm.kt + +actual open class A { + actual open fun foo(arg: T) {} + open fun bar(arg: T): T = arg + open fun baz(arg: T): T = arg +} +class D : C() { + fun test() { + foo("") + bar("") // should be resolved to just C.bar + baz("") + } +} diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.txt new file mode 100644 index 00000000000..71ab100de84 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.ll.txt @@ -0,0 +1,116 @@ +Module: m1-common +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public open expect fun foo(arg: R|T|): R|kotlin/Unit| + + } + public open class B : R|A| { + public constructor(): R|B| { + super|>() + } + + } + public open class C : R|B| { + public constructor(): R|C| { + super() + } + + public open fun bar(arg: R|kotlin/String|): R|kotlin/String| { + ^bar R|/arg| + } + + public open fun baz(arg: R|kotlin/CharSequence|): R|kotlin/String| { + ^baz R|/arg|.R|kotlin/Any.toString|() + } + + } +FILE: jvm.kt + public open actual class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public open actual fun foo(arg: R|T|): R|kotlin/Unit| { + } + + public open fun bar(arg: R|T|): R|T| { + ^bar R|/arg| + } + + public open fun baz(arg: R|T|): R|T| { + ^baz R|/arg| + } + + } + public final class D : R|C| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|SubstitutionOverride|(String()) + this@R|/D|.R|/C.bar|(String()) + this@R|/D|.R|SubstitutionOverride|(String()) + } + + } +Module: m1-jvm +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public open expect fun foo(arg: R|T|): R|kotlin/Unit| + + } + public open class B : R|A| { + public constructor(): R|B| { + super|>() + } + + } + public open class C : R|B| { + public constructor(): R|C| { + super() + } + + public open fun bar(arg: R|kotlin/String|): R|kotlin/String| { + ^bar R|/arg| + } + + public open fun baz(arg: R|kotlin/CharSequence|): R|kotlin/String| { + ^baz R|/arg|.R|kotlin/Any.toString|() + } + + } +FILE: jvm.kt + public open actual class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public open actual fun foo(arg: R|T|): R|kotlin/Unit| { + } + + public open fun bar(arg: R|T|): R|T| { + ^bar R|/arg| + } + + public open fun baz(arg: R|T|): R|T| { + ^baz R|/arg| + } + + } + public final class D : R|C| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|SubstitutionOverride|(String()) + this@R|/D|.R|/C.bar|(String()) + this@R|/D|.R|SubstitutionOverride|(String()) + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt index c3aead86d34..a8be9b2cd0d 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.fir.txt @@ -13,7 +13,61 @@ FILE: common.kt public get(): R|MyList| } -Module: m1-jvm +FILE: jvm.kt + public open actual class MyList : R|kotlin/Any| { + public constructor(): R|MyList| { + super() + } + + public final actual fun get(i: R|kotlin/Int|): R|kotlin/Int| { + ^get R|/i| + } + + public final fun set(i: R|kotlin/Int|, v: R|kotlin/Int|): R|kotlin/Unit| { + } + + } + public final class DerivedList : R|MyList| { + public constructor(): R|DerivedList| { + super() + } + + public final fun useMember(): R|kotlin/Unit| { + this@R|/DerivedList|.R|/MyList.get|(Int(1)) + this@R|/DerivedList|.R|/MyList.set|(Int(2), Int(3)) + } + + } + public final fun useList(list: R|MyList|): R|kotlin/Unit| { + R|/list|.R|/MyList.get|(Int(1)) + R|/list|.R|/MyList.set|(Int(2), Int(3)) + } + public final class DerivedWrapper : R|Wrapper| { + public constructor(): R|DerivedWrapper| { + super(R|/MyList.MyList|()) + } + + public final fun use(): R|kotlin/Unit| { + this@R|/DerivedWrapper|.R|/Wrapper.list|.R|/MyList.get|(Int(1)) + this@R|/DerivedWrapper|.R|/Wrapper.list|.R|/MyList.set|(Int(2), Int(3)) + } + + } +Module: m1-jvm +FILE: common.kt + public final expect class MyList : R|kotlin/Any| { + public final expect fun get(i: R|kotlin/Int|): R|kotlin/Int| + + } + public open class Wrapper : R|kotlin/Any| { + public constructor(list: R|MyList|): R|Wrapper| { + super() + } + + public final val list: R|MyList| = R|/list| + public get(): R|MyList| + + } FILE: jvm.kt public open actual class MyList : R|kotlin/Any| { public constructor(): R|MyList| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.kt index d4b1d2f8b0c..39055488557 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.kt @@ -8,7 +8,7 @@ expect class MyList { open class Wrapper(val list: MyList) -// MODULE: m1-jvm(m1-common) +// MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual open class MyList { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.fir.txt index 55a7148d9c7..da5b293754a 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.fir.txt @@ -15,7 +15,63 @@ FILE: common.kt } } -Module: m1-jvm +FILE: jvm.kt + public open actual class A : R|kotlin/Any| { + public constructor(): R|A| { + super() + } + + public final actual fun foo(): R|kotlin/Unit| { + } + + public final fun bar(): R|kotlin/Unit| { + } + + public final actual val x: R|kotlin/Int| = Int(42) + public get(): R|kotlin/Int| + + } + public final class C : R|B| { + public constructor(): R|C| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/C|.R|/A.foo|() + this@R|/C|.R|/A.bar|() + this@R|/C|.R|/A.x|.R|kotlin/Int.plus|(this@R|/C|.R|/A.x|) + } + + } + public final class D : R|A| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|/A.foo|() + this@R|/D|.R|/A.bar|() + this@R|/D|.R|/A.x|.R|kotlin/Int.plus|(this@R|/D|.R|/A.x|) + } + + } +Module: m1-jvm +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public final expect fun foo(): R|kotlin/Unit| + + public final expect val x: R|kotlin/Int| + public get(): R|kotlin/Int| + + } + public open class B : R|A| { + public constructor(): R|B| { + super() + } + + } FILE: jvm.kt public open actual class A : R|kotlin/Any| { public constructor(): R|A| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt index f978266a1f5..e39b93526cd 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt @@ -10,7 +10,7 @@ expect open class A() { open class B : A() -// MODULE: m1-jvm(m1-common) +// MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt actual open class A { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.fir.txt index 85a21f2b187..321f048c2a0 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.fir.txt @@ -12,7 +12,68 @@ FILE: common.kt } } -Module: m1-jvm +FILE: jvm.kt + public abstract class X : R|kotlin/Any| { + public constructor(): R|X| { + super() + } + + public final fun bar(): R|kotlin/Unit| { + } + + } + public abstract interface Y : R|kotlin/Any| { + public open fun baz(): R|kotlin/Unit| { + } + + } + public open actual class A : R|X|, R|Y| { + public constructor(): R|A| { + super() + } + + public final actual fun foo(): R|kotlin/Unit| { + } + + } + public final class C : R|B| { + public constructor(): R|C| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/C|.R|/A.foo|() + this@R|/C|.R|/X.bar|() + this@R|/C|.R|/Y.baz|() + } + + } + public final class D : R|A| { + public constructor(): R|D| { + super() + } + + public final fun test(): R|kotlin/Unit| { + this@R|/D|.R|/A.foo|() + this@R|/D|.R|/X.bar|() + this@R|/D|.R|/Y.baz|() + } + + } +Module: m1-jvm +FILE: common.kt + public open expect class A : R|kotlin/Any| { + public expect constructor(): R|A| + + public final expect fun foo(): R|kotlin/Unit| + + } + public open class B : R|A| { + public constructor(): R|B| { + super() + } + + } FILE: jvm.kt public abstract class X : R|kotlin/Any| { public constructor(): R|X| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.kt index 2efd920ab41..4ae65d05fb1 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.kt @@ -8,7 +8,7 @@ expect open class A() { open class B : A() -// MODULE: m1-jvm(m1-common) +// MODULE: m1-jvm()()(m1-common) // FILE: jvm.kt abstract class X { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt index 38a01f16c5d..7b802f0b545 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/mpp/FirExpectActualResolver.kt @@ -58,8 +58,10 @@ object FirExpectActualResolver { } } } + val transitiveDependsOn = actualSymbol.moduleData.allDependsOnDependencies candidates.filter { expectSymbol -> - actualSymbol != expectSymbol && (expectContainingClass != null /*match fake overrides*/ || expectSymbol.isExpect) + actualSymbol != expectSymbol && (expectContainingClass != null /*match fake overrides*/ || + expectSymbol.isExpect && expectSymbol.moduleData in transitiveDependsOn) }.groupBy { expectDeclaration -> AbstractExpectActualMatcher.getCallablesMatchingCompatibility( expectDeclaration, @@ -79,7 +81,8 @@ object FirExpectActualResolver { is FirClassLikeSymbol<*> -> { val expectClassSymbol = useSiteSession.dependenciesSymbolProvider .getClassLikeSymbolByClassId(actualSymbol.classId) as? FirRegularClassSymbol ?: return emptyMap() - if (expectClassSymbol.isExpect) { + val transitiveDependsOn = actualSymbol.moduleData.allDependsOnDependencies + if (expectClassSymbol.isExpect && expectClassSymbol.moduleData in transitiveDependsOn) { val compatibility = AbstractExpectActualMatcher.matchClassifiers(expectClassSymbol, actualSymbol, context) mapOf(compatibility to listOf(expectClassSymbol)) } else {