diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt index 32dc97090a1..fc3e2f841f0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirActualCallableDeclarationChecker.kt @@ -10,7 +10,9 @@ import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.expectForActual +import org.jetbrains.kotlin.fir.declarations.getSingleExpectForActualOrNull import org.jetbrains.kotlin.fir.declarations.utils.isActual import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -45,7 +47,8 @@ object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() { if (!areCompatibleExpectActualTypes( substitutor.substituteOrSelf(expectFunctionSymbol.resolvedReturnType.type), actualFunctionSymbol.resolvedReturnType.type, - context.session + context.session, + dynamicTypesEqualToAnything = false ) ) { reporter.reportOn( diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt index 281f344ffea..fb5ed751dcc 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/ExpectActualUtils.kt @@ -34,11 +34,20 @@ fun createExpectActualTypeParameterSubstitutor( fun areCompatibleExpectActualTypes( expectedType: ConeKotlinType?, actualType: ConeKotlinType?, - actualSession: FirSession + actualSession: FirSession, + dynamicTypesEqualToAnything: Boolean = true ): Boolean { if (expectedType == null) return actualType == null if (actualType == null) return false + if (!dynamicTypesEqualToAnything) { + val isExpectedDynamic = expectedType is ConeDynamicType + val isActualDynamic = actualType is ConeDynamicType + if (isExpectedDynamic && !isActualDynamic || !isExpectedDynamic && isActualDynamic) { + return false + } + } + return AbstractTypeChecker.equalTypes( actualSession.typeContext, expectedType, diff --git a/compiler/testData/diagnostics/tests/multiplatform/implDynamic.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.fir.kt new file mode 100644 index 00000000000..d86144d2ae5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.fir.kt @@ -0,0 +1,28 @@ +// !DIAGNOSTICS: -UNSUPPORTED +// MODULE: m1-common +// FILE: common.kt + +expect class Foo { + constructor(p: Any) + + fun f1(s: String): Int + + fun f2(s: List?): MutableMap + + fun > f3(t: T): T? +} + +// MODULE: m2-js()()(m1-common) +// FILE: js.kt + +// TODO: do not suppress UNSUPPORTED once JS files in multi-platform tests are analyzed with JS analyzer facade + +actual class Foo { + actual constructor(p: dynamic) {} + + actual fun f1(s: dynamic): dynamic = null!! + + actual fun f2(s: dynamic): MutableMap = null!! + + actual fun > f3(t: T): dynamic = null!! +} diff --git a/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt index 7ecc503897e..7d4289cd403 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/implDynamic.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !DIAGNOSTICS: -UNSUPPORTED // MODULE: m1-common // FILE: common.kt