diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.dynamic.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.dynamic.txt index 70c99ca2455..986d3a77e00 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.dynamic.txt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.dynamic.txt @@ -14,9 +14,7 @@ public final fun contains(/*0*/ p0: dynamic): dynamic public final fun contains(/*0*/ p0: dynamic): dynamic public final fun contains(/*0*/ p0: dynamic): dynamic public final fun get(/*0*/ p0: dynamic): dynamic -public final fun get(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic public final fun set(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic -public final fun set(/*0*/ p0: dynamic, /*1*/ p1: dynamic, /*2*/ p2: dynamic): dynamic public final fun get(/*0*/ p0: dynamic): dynamic public final fun inc(): dynamic public final fun inc(): dynamic diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.kt index 051becac757..d42298fdf5d 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/conventions.kt @@ -27,10 +27,8 @@ fun test(d: dynamic) { 1 !in d d[1] - d[1, 2] d[1] = 2 - d[1, 2] = 3 d[1]++ ++d[1] diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.dynamic.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.dynamic.txt new file mode 100644 index 00000000000..0ab2de1ce5e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.dynamic.txt @@ -0,0 +1,4 @@ +public final fun get(/*0*/ p0: dynamic): dynamic +public final fun get(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic +public final fun set(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic +public final fun set(/*0*/ p0: dynamic, /*1*/ p1: dynamic, /*2*/ p2: dynamic): dynamic diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.kt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.kt new file mode 100644 index 00000000000..7aa077f205d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.kt @@ -0,0 +1,8 @@ +fun foo() { + val a: dynamic = Any() + println(a[0]) + println(a[0, 1]) + + a[0] = 23 + a[0, 1] = 42 +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.txt new file mode 100644 index 00000000000..65a6ac47e1f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.txt @@ -0,0 +1,3 @@ +package + +public fun foo(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index c8462fcc269..f1804ea5bee 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -146,6 +146,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes doTest(fileName); } + @TestMetadata("indexedAccess.kt") + public void testIndexedAccess() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/indexedAccess.kt"); + doTest(fileName); + } + @TestMetadata("inference.kt") public void testInference() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/inference.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 0a8b1a7e1af..eff6640e4c4 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 @@ -38,7 +38,7 @@ object JsPlatformConfigurator : PlatformConfigurator( PlatformImplDeclarationChecker(), JsExternalChecker() ), - additionalCallCheckers = listOf(ReifiedTypeParameterSubstitutionChecker(), JsModuleCallChecker), + additionalCallCheckers = listOf(ReifiedTypeParameterSubstitutionChecker(), JsModuleCallChecker, JsDynamicCallChecker), additionalTypeCheckers = listOf(), additionalClassifierUsageCheckers = listOf(), additionalAnnotationCheckers = listOf(), 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 6ab90cf1999..ce2f3f091f3 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 @@ -62,6 +62,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { 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} for reified type parameter", RENDER_TYPE) + put(ErrorsJs.WRONG_OPERATION_WITH_DYNAMIC, "Wrong operation with dynamic value: {0}", Renderers.STRING) 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 7f8249eb762..257698c0b0c 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 @@ -61,6 +61,7 @@ public interface ErrorsJs { 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); + DiagnosticFactory1 WRONG_OPERATION_WITH_DYNAMIC = DiagnosticFactory1.create(ERROR); @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsDynamicCallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsDynamicCallChecker.kt new file mode 100644 index 00000000000..8408081a19a --- /dev/null +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsDynamicCallChecker.kt @@ -0,0 +1,36 @@ +/* + * 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.psi.KtArrayAccessExpression +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.types.isDynamic + +object JsDynamicCallChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + val callee = resolvedCall.resultingDescriptor + if (callee.dispatchReceiverParameter?.type?.isDynamic() != true) return + + val element = resolvedCall.call.callElement + if (element is KtArrayAccessExpression && element.indexExpressions.size > 1) { + context.trace.report(ErrorsJs.WRONG_OPERATION_WITH_DYNAMIC.on(reportOn, "indexed access with more than one index")) + } + } +} \ No newline at end of file