diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.kt b/compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.kt new file mode 100644 index 00000000000..e913ef8db8b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.kt @@ -0,0 +1,21 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +inline fun foo(x: T) { + println(x) +} + +@native interface I + +@native class C : I + +operator inline fun C.plus(other: T) = this + +fun bar() { + foo(C()) + + val c: I = C() + foo(c) + foo<I>(C()) + + C() + c +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.txt b/compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.txt new file mode 100644 index 00000000000..67e498a167e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.txt @@ -0,0 +1,18 @@ +package + +public fun bar(): kotlin.Unit +public inline fun foo(/*0*/ x: T): kotlin.Unit +public operator inline fun C.plus(/*0*/ other: T): C + +@kotlin.js.native() public final class C : I { + 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@kotlin.js.native() public interface I { + 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*/ /*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 89b4c126f72..a9bfc03f889 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -739,6 +739,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes doTest(fileName); } + @TestMetadata("nativeInterfaceAsReifiedTypeArgument.kt") + public void testNativeInterfaceAsReifiedTypeArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/nativeInterfaceAsReifiedTypeArgument.kt"); + doTest(fileName); + } + @TestMetadata("whenIsNativeInterface.kt") public void testWhenIsNativeInterface() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/rtti/whenIsNativeInterface.kt"); diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index ce349fa8586..0ba612c3a7f 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker import org.jetbrains.kotlin.js.resolve.diagnostics.JsNameChecker import org.jetbrains.kotlin.js.resolve.diagnostics.JsNameClashChecker import org.jetbrains.kotlin.js.resolve.diagnostics.JsNativeRttiChecker +import org.jetbrains.kotlin.js.resolve.diagnostics.JsReifiedNativeChecker import org.jetbrains.kotlin.js.resolve.diagnostics.NativeInnerClassChecker import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap import org.jetbrains.kotlin.resolve.IdentifierChecker @@ -53,5 +54,6 @@ object JsPlatformConfigurator : PlatformConfigurator( container.useInstance(JsNameClashChecker()) container.useImpl() container.useImpl() + container.useImpl() } } 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 7e0debb6b3d..dfe250002ce 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 @@ -50,6 +50,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { put(ErrorsJs.JS_NAME_PROHIBITED_FOR_NAMED_NATIVE, "@JsName is prohibited for @native declaration with explicit name") put(ErrorsJs.CANNOT_CHECK_FOR_NATIVE_INTERFACE, "Cannot check for native interface: {0}", RENDER_TYPE) put(ErrorsJs.UNCHECKED_CAST_TO_NATIVE_INTERFACE, "Unchecked cast to native interface: {0} to {1}", RENDER_TYPE, RENDER_TYPE) + put(ErrorsJs.NATIVE_INTERFACE_AS_REIFIED_TYPE_ARGUMENT, "Cannot pass native interface {0} to reified type parameter", RENDER_TYPE) 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 46fdac52eb7..8a93845a89e 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 @@ -54,6 +54,7 @@ public interface ErrorsJs { DiagnosticFactory0 JS_NAME_PROHIBITED_FOR_NAMED_NATIVE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 CANNOT_CHECK_FOR_NATIVE_INTERFACE = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 UNCHECKED_CAST_TO_NATIVE_INTERFACE = DiagnosticFactory2.create(WARNING); + DiagnosticFactory1 NATIVE_INTERFACE_AS_REIFIED_TYPE_ARGUMENT = DiagnosticFactory1.create(ERROR); @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNativeRttiChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNativeRttiChecker.kt index 37e3a2cad4d..ce033a59706 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNativeRttiChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNativeRttiChecker.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.resolve.diagnostics import com.intellij.psi.PsiElement import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionChecker import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionInformation import org.jetbrains.kotlin.resolve.calls.checkers.RttiOperation diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReifiedNativeChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReifiedNativeChecker.kt new file mode 100644 index 00000000000..167860771f2 --- /dev/null +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReifiedNativeChecker.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.resolve.diagnostics + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall + +class JsReifiedNativeChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + val typeArgumentList = resolvedCall.call.typeArgumentList?.arguments + for ((typeParam, typeArg) in resolvedCall.typeArguments) { + if (!typeParam.isReified) continue + + val typeArgDescriptor = typeArg.constructor.declarationDescriptor + if (typeArgDescriptor != null && AnnotationsUtils.isNativeInterface(typeArgDescriptor)) { + val typeArgumentPsi = if (typeArgumentList != null) { + typeArgumentList[typeParam.index].typeReference + } + else { + resolvedCall.call.valueArguments[typeParam.index].getArgumentExpression() + } + + context.trace.report(ErrorsJs.NATIVE_INTERFACE_AS_REIFIED_TYPE_ARGUMENT.on(typeArgumentPsi!!, typeArg)) + } + } + } +} \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index d12ea576cb8..b479765e9ae 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -5570,6 +5570,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { doTest(fileName); } + @TestMetadata("nativeClassAsReifiedTypeArgument.kt") + public void testNativeClassAsReifiedTypeArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/nativeClassAsReifiedTypeArgument.kt"); + doTest(fileName); + } + @TestMetadata("nativeExtensionLikeMember.kt") public void testNativeExtensionLikeMember() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/nativeExtensionLikeMember.kt"); diff --git a/js/js.translator/testData/box/native/nativeClassAsReifiedTypeArgument.kt b/js/js.translator/testData/box/native/nativeClassAsReifiedTypeArgument.kt new file mode 100644 index 00000000000..cb42a9dec6b --- /dev/null +++ b/js/js.translator/testData/box/native/nativeClassAsReifiedTypeArgument.kt @@ -0,0 +1,25 @@ +//FILE: nativeClassAsReifiedTypeArgument.kt + +var global = "" + +inline fun log(x: T) { + global += jsClass().name + ": " + x +} + +@native class C { + override fun toString() = noImpl +} + +fun box(): String { + log(C()) + if (global != "C: C instance") return "fail: $global" + return "OK" +} + +//FILE: nativeClassAsReifiedTypeArgument.js + +function C() { +} +C.prototype.toString = function() { + return "C instance" +} \ No newline at end of file