diff --git a/compiler/testData/codegen/box/functions/invoke/kt3190.kt b/compiler/testData/codegen/box/functions/invoke/kt3190.kt index 17c2e94db49..e5191fff338 100644 --- a/compiler/testData/codegen/box/functions/invoke/kt3190.kt +++ b/compiler/testData/codegen/box/functions/invoke/kt3190.kt @@ -1,4 +1,6 @@ //KT-3190 Compiler crash if function called 'invoke' calls a closure +// IGNORE_BACKEND: JS +// JS backend does not allow to implement Function{N} interfaces fun box(): String { val test = Cached({ it + 2 }) diff --git a/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt b/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt index 3a3067e2e99..7d8bb7ef55c 100644 --- a/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt +++ b/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt @@ -1,4 +1,6 @@ //KT-3822 Compiler crashes when use invoke convention with `this` in class which extends Function0 +// IGNORE_BACKEND: JS +// JS backend does not allow to implement Function{N} interfaces class B() : Function0 { override fun invoke() = true diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt b/compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt new file mode 100644 index 00000000000..375553c5ecd --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt @@ -0,0 +1,9 @@ +abstract class A : () -> Unit + +object B : (String, Int) -> Long { + override fun invoke(a: String, B: Int) = 23L +} + +abstract class C : kotlin.Function1 + +abstract class D : C() \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.txt b/compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.txt new file mode 100644 index 00000000000..ca258e4cbb2 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.txt @@ -0,0 +1,33 @@ +package + +public abstract class A : () -> kotlin.Unit { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun invoke(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object B : (kotlin.String, kotlin.Int) -> kotlin.Long { + private constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ fun invoke(/*0*/ a: kotlin.String, /*1*/ B: kotlin.Int): kotlin.Long + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class C : (kotlin.Any) -> kotlin.Int { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun invoke(/*0*/ p1: kotlin.Any): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class D : C { + public constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract override /*1*/ /*fake_override*/ fun invoke(/*0*/ p1: kotlin.Any): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index 16d19a588a9..38d112604f7 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -36,6 +36,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("implementingFunction.kt") + public void testImplementingFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt"); + doTest(fileName); + } + @TestMetadata("localClassMetadata.kt") public void testLocalClassMetadata() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt"); diff --git a/core/builtins/src/kotlin/reflect/KProperty.kt b/core/builtins/src/kotlin/reflect/KProperty.kt index ace48795a4b..0ba33ca9c62 100644 --- a/core/builtins/src/kotlin/reflect/KProperty.kt +++ b/core/builtins/src/kotlin/reflect/KProperty.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:Suppress("IMPLEMENTING_FUNCTION_INTERFACE") package kotlin.reflect /** diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt index dfc3100a3b6..e78fb69530d 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt @@ -71,6 +71,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { put(ErrorsJs.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS, "Overriding `external` function with optional parameters") put(ErrorsJs.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE, "Overriding `external` function with optional parameters by declaration from superclass: {0}", Renderers.COMPACT) + put(ErrorsJs.IMPLEMENTING_FUNCTION_INTERFACE, "Implementing function interface is prohibited in JavaScript") this } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java index a7c4b98f803..3475859f375 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.diagnostics.*; +import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.psi.KtDeclaration; import org.jetbrains.kotlin.psi.KtElement; import org.jetbrains.kotlin.psi.KtExpression; @@ -73,6 +74,8 @@ public interface ErrorsJs { DiagnosticFactory0.create(ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory1 OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE = DiagnosticFactory1.create(ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT); + DiagnosticFactory0 IMPLEMENTING_FUNCTION_INTERFACE = DiagnosticFactory0.create( + ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT); @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt index 5b23952d09a..7d0de83e4d9 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt @@ -16,14 +16,20 @@ package org.jetbrains.kotlin.js.resolve.diagnostics -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes object JsInheritanceChecker : SimpleDeclarationChecker { override fun check( @@ -44,6 +50,12 @@ object JsInheritanceChecker : SimpleDeclarationChecker { declaration, fakeOverriddenMethod)) } } + + if (descriptor is ClassDescriptor && + descriptor.defaultType.immediateSupertypes().any { it.isBuiltinFunctionalTypeOrSubtype } + ) { + diagnosticHolder.report(ErrorsJs.IMPLEMENTING_FUNCTION_INTERFACE.on(declaration as KtClassOrObject)) + } } private fun isOverridingExternalWithOptionalParams(function: FunctionDescriptor): Boolean { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 00033fdfa0c..7c774e023e7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -8870,7 +8870,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("kt3190.kt") public void testKt3190() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/invoke/kt3190.kt"); - doTest(fileName); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } @TestMetadata("kt3297.kt") @@ -8906,7 +8912,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("kt3822invokeOnThis.kt") public void testKt3822invokeOnThis() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt"); - doTest(fileName); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } }