diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt index 17edee1f752..804d14e43ab 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/HeaderImplDeclarationChecker.kt @@ -292,7 +292,9 @@ object HeaderImplDeclarationChecker : DeclarationChecker { object TypeParameterNames : Incompatible("names of type parameters are different") object ValueParameterHasDefault : Incompatible("some parameters have default values") - object ValueParameterModifiers : Incompatible("parameter modifiers are different (vararg, coroutine, crossinline, noinline)") + object ValueParameterVararg : Incompatible("some value parameter is vararg in one declaration and non-vararg in the other") + object ValueParameterNoinline : Incompatible("some value parameter is noinline in one declaration and not noinline in the other") + object ValueParameterCrossinline : Incompatible("some value parameter is crossinline in one declaration and not crossinline in the other") // Functions @@ -376,7 +378,13 @@ object HeaderImplDeclarationChecker : DeclarationChecker { areCompatibleTypeParameters(aTypeParams, bTypeParams, platformModule, substitutor).let { if (it != Compatible) return it } if (!equalsBy(aParams, bParams, ValueParameterDescriptor::declaresDefaultValue)) return Incompatible.ValueParameterHasDefault - if (!equalsBy(aParams, bParams, { p -> listOf(p.varargElementType != null, p.isCrossinline, p.isNoinline) })) return Incompatible.ValueParameterModifiers + if (!equalsBy(aParams, bParams, { p -> listOf(p.varargElementType != null) })) return Incompatible.ValueParameterVararg + + // Adding noinline/crossinline to parameters is disallowed, except if the header declaration was not inline at all + if (a is FunctionDescriptor && a.isInline) { + if (aParams.indices.any { i -> !aParams[i].isNoinline && bParams[i].isNoinline }) return Incompatible.ValueParameterNoinline + if (aParams.indices.any { i -> !aParams[i].isCrossinline && bParams[i].isCrossinline }) return Incompatible.ValueParameterCrossinline + } when { a is FunctionDescriptor && b is FunctionDescriptor -> areCompatibleFunctions(a, b).let { if (it != Compatible) return it } @@ -443,7 +451,9 @@ object HeaderImplDeclarationChecker : DeclarationChecker { if (!areCompatibleTypeLists(a.map { substitutor(it.defaultType) }, b.map { it.defaultType }, platformModule)) return Incompatible.TypeParameterUpperBounds if (!equalsBy(a, b, TypeParameterDescriptor::getVariance)) return Incompatible.TypeParameterVariance - if (!equalsBy(a, b, TypeParameterDescriptor::isReified)) return Incompatible.TypeParameterReified + + // Removing "reified" from a header function's type parameter is fine + if (a.indices.any { i -> !a[i].isReified && b[i].isReified }) return Incompatible.TypeParameterReified return Compatible } diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.kt new file mode 100644 index 00000000000..87c2a7fc5ea --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.kt @@ -0,0 +1,27 @@ +// !LANGUAGE: +MultiPlatformProjects +// !DIAGNOSTICS: -NOTHING_TO_INLINE +// MODULE: m1-common +// FILE: common.kt + +header fun f1(s: () -> String) +header inline fun f2(s: () -> String) +header inline fun f3(noinline s: () -> String) + +header fun f4(s: () -> String) +header inline fun f5(s: () -> String) +header inline fun f6(crossinline s: () -> String) + +header fun f7(x: Any) +header fun f8(vararg x: Any) + +// MODULE: m2-jvm(m1-common) +// FILE: jvm.kt + +impl inline fun f1(noinline s: () -> String) {} +impl inline fun f2(noinline s: () -> String) {} +impl inline fun f3(s: () -> String) {} +impl inline fun f4(crossinline s: () -> String) {} +impl inline fun f5(crossinline s: () -> String) {} +impl inline fun f6(s: () -> String) {} +impl fun f7(vararg x: Any) {} +impl fun f8(x: Any) {} diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.txt b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.txt new file mode 100644 index 00000000000..a3c04e261ee --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.txt @@ -0,0 +1,24 @@ +// -- Module: -- +package + +public header fun f1(/*0*/ s: () -> kotlin.String): kotlin.Unit +public header inline fun f2(/*0*/ s: () -> kotlin.String): kotlin.Unit +public header inline fun f3(/*0*/ noinline s: () -> kotlin.String): kotlin.Unit +public header fun f4(/*0*/ s: () -> kotlin.String): kotlin.Unit +public header inline fun f5(/*0*/ s: () -> kotlin.String): kotlin.Unit +public header inline fun f6(/*0*/ crossinline s: () -> kotlin.String): kotlin.Unit +public header fun f7(/*0*/ x: kotlin.Any): kotlin.Unit +public header fun f8(/*0*/ vararg x: kotlin.Any /*kotlin.Array*/): kotlin.Unit + + +// -- Module: -- +package + +public impl inline fun f1(/*0*/ noinline s: () -> kotlin.String): kotlin.Unit +public impl inline fun f2(/*0*/ noinline s: () -> kotlin.String): kotlin.Unit +public impl inline fun f3(/*0*/ s: () -> kotlin.String): kotlin.Unit +public impl inline fun f4(/*0*/ crossinline s: () -> kotlin.String): kotlin.Unit +public impl inline fun f5(/*0*/ crossinline s: () -> kotlin.String): kotlin.Unit +public impl inline fun f6(/*0*/ s: () -> kotlin.String): kotlin.Unit +public impl fun f7(/*0*/ vararg x: kotlin.Any /*kotlin.Array*/): kotlin.Unit +public impl fun f8(/*0*/ x: kotlin.Any): kotlin.Unit diff --git a/compiler/testData/multiplatform/incompatibleCallables/common.kt b/compiler/testData/multiplatform/incompatibleCallables/common.kt index 4777bc428df..8741cb2e7d1 100644 --- a/compiler/testData/multiplatform/incompatibleCallables/common.kt +++ b/compiler/testData/multiplatform/incompatibleCallables/common.kt @@ -1,5 +1,3 @@ -import kotlin.coroutines.experimental.* - header fun f1() header fun f2(name: String) @@ -21,7 +19,7 @@ public header fun f10() header fun f11() header fun > f12() -header fun > f13() +header fun > f13() header inline fun f14() header inline fun f15() @@ -30,9 +28,7 @@ header fun f16(s: String) header fun f17(vararg s: String) header fun f18(s: Array) -header inline fun f19(crossinline s: () -> Unit) +header inline fun f19(s: () -> Unit) header inline fun f20(s: () -> Unit) -header inline fun f21(noinline s: () -> Unit) -header inline fun f22(s: () -> Unit) -header fun f23(c: suspend Unit.() -> Unit) -header fun f24(c: Unit.() -> Unit) +header fun f21(c: suspend Unit.() -> Unit) +header fun f22(c: Unit.() -> Unit) diff --git a/compiler/testData/multiplatform/incompatibleCallables/jvm.kt b/compiler/testData/multiplatform/incompatibleCallables/jvm.kt index c6fb10abbae..38e5269119e 100644 --- a/compiler/testData/multiplatform/incompatibleCallables/jvm.kt +++ b/compiler/testData/multiplatform/incompatibleCallables/jvm.kt @@ -1,5 +1,3 @@ -import kotlin.coroutines.experimental.* - impl fun f1(): String = "" impl fun f2(otherName: String) {} @@ -21,7 +19,7 @@ private impl fun f10() {} impl fun f11() {} impl fun > f12() {} -impl fun > f13() {} +impl fun > f13() {} impl inline fun f14() {} impl inline fun f15() {} @@ -30,9 +28,7 @@ impl fun f16(s: String = "") {} impl fun f17(s: Array) {} impl fun f18(vararg s: String) {} -impl inline fun f19(s: () -> Unit) {} -impl inline fun f20(crossinline s: () -> Unit) {} -impl inline fun f21(s: () -> Unit) {} -impl inline fun f22(noinline s: () -> Unit) {} -impl fun f23(c: Unit.() -> Unit) {} -impl fun f24(c: suspend Unit.() -> Unit) {} +impl inline fun f19(crossinline s: () -> Unit) {} +impl inline fun f20(noinline s: () -> Unit) {} +impl fun f21(c: Unit.() -> Unit) {} +impl fun f22(c: suspend Unit.() -> Unit) {} diff --git a/compiler/testData/multiplatform/incompatibleCallables/output.txt b/compiler/testData/multiplatform/incompatibleCallables/output.txt index 8b4591ba396..289610214c9 100644 --- a/compiler/testData/multiplatform/incompatibleCallables/output.txt +++ b/compiler/testData/multiplatform/incompatibleCallables/output.txt @@ -1,145 +1,124 @@ -- Common -- -Exit code: COMPILATION_ERROR +Exit code: OK Output: -compiler/testData/multiplatform/incompatibleCallables/common.kt:1:15: error: unresolved reference: coroutines -import kotlin.coroutines.experimental.* - ^ -compiler/testData/multiplatform/incompatibleCallables/common.kt:24:20: error: unresolved reference: Continuation -header fun > f13() - ^ +compiler/testData/multiplatform/incompatibleCallables/common.kt:33:19: warning: the feature "coroutines" is experimental (see: https://kotlinlang.org/docs/diagnostics/experimental-coroutines) +header fun f21(c: suspend Unit.() -> Unit) + ^ -- JVM -- Exit code: COMPILATION_ERROR Output: -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:3:1: error: 'impl' function 'f1' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:1:1: error: 'impl' function 'f1' has no corresponding 'header' declaration The following declaration is incompatible because return type is different: public header fun f1(): Unit impl fun f1(): String = "" ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:5:1: error: 'impl' function 'f2' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:3:1: error: 'impl' function 'f2' has no corresponding 'header' declaration The following declaration is incompatible because parameter names are different: public header fun f2(name: String): Unit impl fun f2(otherName: String) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:7:1: error: 'impl' function 'f3' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:5:1: error: 'impl' function 'f3' has no corresponding 'header' declaration The following declaration is incompatible because parameter types are different: public header fun f3(name: String): Unit impl fun f3(name: Double) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:8:1: error: 'impl' function 'f3ext' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:6:1: error: 'impl' function 'f3ext' has no corresponding 'header' declaration The following declaration is incompatible because parameter types are different: public header fun String.f3ext(): Unit impl fun Double.f3ext() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:10:1: error: 'impl' function 'f4' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:8:1: error: 'impl' function 'f4' has no corresponding 'header' declaration The following declaration is incompatible because parameter shapes are different (extension vs non-extension): public header fun f4(name: String): Unit impl fun String.f4() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:12:1: error: 'impl' function 'f5' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:10:1: error: 'impl' function 'f5' has no corresponding 'header' declaration The following declaration is incompatible because parameter shapes are different (extension vs non-extension): public header fun String.f5(): Unit impl fun f5(name: String) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:14:1: error: 'impl' function 'f6' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:12:1: error: 'impl' function 'f6' has no corresponding 'header' declaration The following declaration is incompatible because number of value parameters is different: public header fun f6(p1: String, p2: Int): Unit impl fun f6(p2: Int) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:16:1: error: 'impl' function 'f7' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:14:1: error: 'impl' function 'f7' has no corresponding 'header' declaration The following declaration is incompatible because number of type parameters is different: public header fun f7(): Unit impl fun f7() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:18:1: error: 'impl' function 'f8' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:16:1: error: 'impl' function 'f8' has no corresponding 'header' declaration The following declaration is incompatible because visibility is different: internal header fun f8(): Unit public impl fun f8() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:19:1: error: 'impl' function 'f9' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:17:1: error: 'impl' function 'f9' has no corresponding 'header' declaration The following declaration is incompatible because visibility is different: private header fun f9(): Unit internal impl fun f9() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:20:1: error: 'impl' function 'f10' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:18:1: error: 'impl' function 'f10' has no corresponding 'header' declaration The following declaration is incompatible because visibility is different: public header fun f10(): Unit private impl fun f10() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:26:1: error: 'impl' function 'f14' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:24:1: error: 'impl' function 'f14' has no corresponding 'header' declaration The following declaration is incompatible because some type parameter is reified in one declaration and non-reified in the other: public header inline fun f14(): Unit impl inline fun f14() {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:27:1: error: 'impl' function 'f15' has no corresponding 'header' declaration -The following declaration is incompatible because some type parameter is reified in one declaration and non-reified in the other: - public header inline fun f15(): Unit - -impl inline fun f15() {} -^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:29:1: error: 'impl' function 'f16' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:27:1: error: 'impl' function 'f16' has no corresponding 'header' declaration The following declaration is incompatible because some parameters have default values: public header fun f16(s: String): Unit impl fun f16(s: String = "") {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:31:1: error: 'impl' function 'f17' has no corresponding 'header' declaration -The following declaration is incompatible because parameter modifiers are different (vararg, coroutine, crossinline, noinline): +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:29:1: error: 'impl' function 'f17' has no corresponding 'header' declaration +The following declaration is incompatible because some value parameter is vararg in one declaration and non-vararg in the other: public header fun f17(vararg s: String): Unit impl fun f17(s: Array) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:32:1: error: 'impl' function 'f18' has no corresponding 'header' declaration -The following declaration is incompatible because parameter modifiers are different (vararg, coroutine, crossinline, noinline): +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:30:1: error: 'impl' function 'f18' has no corresponding 'header' declaration +The following declaration is incompatible because some value parameter is vararg in one declaration and non-vararg in the other: public header fun f18(s: Array): Unit impl fun f18(vararg s: String) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:33:1: error: 'impl' function 'f19' has no corresponding 'header' declaration -The following declaration is incompatible because parameter modifiers are different (vararg, coroutine, crossinline, noinline): - public header inline fun f19(crossinline s: () -> Unit): Unit +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:31:1: error: 'impl' function 'f19' has no corresponding 'header' declaration +The following declaration is incompatible because some value parameter is crossinline in one declaration and not crossinline in the other: + public header inline fun f19(s: () -> Unit): Unit -impl inline fun f19(s: () -> Unit) {} +impl inline fun f19(crossinline s: () -> Unit) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:34:1: error: 'impl' function 'f20' has no corresponding 'header' declaration -The following declaration is incompatible because parameter modifiers are different (vararg, coroutine, crossinline, noinline): +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:32:1: error: 'impl' function 'f20' has no corresponding 'header' declaration +The following declaration is incompatible because some value parameter is noinline in one declaration and not noinline in the other: public header inline fun f20(s: () -> Unit): Unit -impl inline fun f20(crossinline s: () -> Unit) {} +impl inline fun f20(noinline s: () -> Unit) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:35:1: error: 'impl' function 'f21' has no corresponding 'header' declaration -The following declaration is incompatible because parameter modifiers are different (vararg, coroutine, crossinline, noinline): - public header inline fun f21(noinline s: () -> Unit): Unit - -impl inline fun f21(s: () -> Unit) {} -^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:36:1: error: 'impl' function 'f22' has no corresponding 'header' declaration -The following declaration is incompatible because parameter modifiers are different (vararg, coroutine, crossinline, noinline): - public header inline fun f22(s: () -> Unit): Unit - -impl inline fun f22(noinline s: () -> Unit) {} -^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:37:1: error: 'impl' function 'f23' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:33:1: error: 'impl' function 'f21' has no corresponding 'header' declaration The following declaration is incompatible because parameter types are different: - public header fun f23(c: suspend Unit.() -> Unit): Unit + public header fun f21(c: suspend Unit.() -> Unit): Unit -impl fun f23(c: Unit.() -> Unit) {} +impl fun f21(c: Unit.() -> Unit) {} ^ -compiler/testData/multiplatform/incompatibleCallables/jvm.kt:38:1: error: 'impl' function 'f24' has no corresponding 'header' declaration +compiler/testData/multiplatform/incompatibleCallables/jvm.kt:34:1: error: 'impl' function 'f22' has no corresponding 'header' declaration The following declaration is incompatible because parameter types are different: - public header fun f24(c: Unit.() -> Unit): Unit + public header fun f22(c: Unit.() -> Unit): Unit -impl fun f24(c: suspend Unit.() -> Unit) {} +impl fun f22(c: suspend Unit.() -> Unit) {} ^ diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index ae351734eb6..d8a237bb2b1 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -13907,6 +13907,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/topLevelFun/simpleHeaderFun.kt"); doTest(fileName); } + + @TestMetadata("valueParameterModifiers.kt") + public void testValueParameterModifiers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/multiplatform/topLevelFun/valueParameterModifiers.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/topLevelProperty")