From 9d0b880f674798d80356505ac68d712f2269cbe0 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Tue, 21 Aug 2018 12:11:26 +0300 Subject: [PATCH] [JS FE] Prohibit inline classes as parameter type and return type of external declarations #KT-26171 Fixed --- .../inlineClassAsParameterOrReturnType.kt.kt | 64 +++++++++++++++++ .../inlineClassAsParameterOrReturnType.kt.txt | 69 +++++++++++++++++++ .../DiagnosticsTestWithJsStdLibGenerated.java | 5 ++ .../diagnostics/DefaultErrorMessagesJs.kt | 16 +---- .../js/resolve/diagnostics/ErrorsJs.java | 16 +---- .../resolve/diagnostics/JsExternalChecker.kt | 25 +++++++ 6 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.kt create mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.txt diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.kt b/compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.kt new file mode 100644 index 00000000000..c694bc7e93b --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.kt @@ -0,0 +1,64 @@ +// !LANGUAGE: +InlineClasses + +// FILE: uint.kt + +package kotlin + +inline class UInt(private val i: Int) + +// FILE: test.kt + +inline class SomeIC(val a: Int) + +external val l: SomeIC + +external val ll + get(): SomeIC = definedExternally + +external var r: SomeIC + +external var rr: SomeIC + get() = definedExternally + set(v: SomeIC) { definedExternally } + +external fun foo(): SomeIC +external fun foo(c: SomeIC): SomeIC +external fun foo(a: Int, c: SomeIC): SomeIC + +external fun foo(a: Int, vararg args: SomeIC) +external fun foo(a: Int, ui: UInt, vararg args: UInt) + +external class CC( + a: SomeIC, + val b: SomeIC, + var c: SomeIC +) { + val l: SomeIC + var r: SomeIC + + fun foo(): SomeIC + fun foo(c: SomeIC): SomeIC + fun foo(a: Int, c: SomeIC): SomeIC + + class N( + a: SomeIC, + val b: SomeIC, + var c: SomeIC + ) { + val l: SomeIC + var r: SomeIC + + fun foo(): SomeIC + fun foo(c: SomeIC): SomeIC + fun foo(a: Int, c: SomeIC): SomeIC + } +} + +external interface EI { + val l: SomeIC + var r: SomeIC + + fun foo(): SomeIC + fun foo(c: SomeIC): SomeIC + fun foo(a: Int, c: SomeIC): SomeIC +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.txt b/compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.txt new file mode 100644 index 00000000000..6c864e7c782 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.txt @@ -0,0 +1,69 @@ +package + +public external val l: SomeIC +public external val ll: SomeIC +public external var r: SomeIC +public external var rr: SomeIC +public external fun foo(): SomeIC +public external fun foo(/*0*/ c: SomeIC): SomeIC +public external fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC +public external fun foo(/*0*/ a: kotlin.Int, /*1*/ vararg args: SomeIC /*kotlin.Array*/): kotlin.Unit +public external fun foo(/*0*/ a: kotlin.Int, /*1*/ ui: kotlin.UInt, /*2*/ vararg args: kotlin.UInt /*kotlin.Array*/): kotlin.Unit + +public final external class CC { + public constructor CC(/*0*/ a: SomeIC, /*1*/ b: SomeIC, /*2*/ c: SomeIC) + public final val b: SomeIC + public final var c: SomeIC + public final val l: SomeIC + public final var r: SomeIC + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(): SomeIC + public final fun foo(/*0*/ c: SomeIC): SomeIC + public final fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class N { + public constructor N(/*0*/ a: SomeIC, /*1*/ b: SomeIC, /*2*/ c: SomeIC) + public final val b: SomeIC + public final var c: SomeIC + public final val l: SomeIC + public final var r: SomeIC + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun foo(): SomeIC + public final fun foo(/*0*/ c: SomeIC): SomeIC + public final fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public external interface EI { + public abstract val l: SomeIC + public abstract var r: SomeIC + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): SomeIC + public abstract fun foo(/*0*/ c: SomeIC): SomeIC + public abstract fun foo(/*0*/ a: kotlin.Int, /*1*/ c: SomeIC): SomeIC + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final inline class SomeIC { + public constructor SomeIC(/*0*/ a: kotlin.Int) + public final val a: kotlin.Int + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} + +package kotlin { + + public final inline class UInt { + public constructor UInt(/*0*/ i: kotlin.Int) + private final val i: kotlin.Int + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ 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 6807f095843..a24c80a2768 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -664,6 +664,11 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes runTest("compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClass.kt"); } + @TestMetadata("inlineClassAsParameterOrReturnType.kt.kt") + public void testInlineClassAsParameterOrReturnType_kt() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJsStdLib/native/inlineClassAsParameterOrReturnType.kt.kt"); + } + @TestMetadata("inlineExtensionToNative.kt") public void testInlineExtensionToNative() throws Exception { runTest("compiler/testData/diagnostics/testsWithJsStdLib/native/inlineExtensionToNative.kt"); 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 58b2fb54062..9680f6d4e8a 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 @@ -1,17 +1,6 @@ /* - * 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. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.js.resolve.diagnostics @@ -39,6 +28,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { put(ErrorsJs.NESTED_EXTERNAL_DECLARATION, "Non top-level `external` declaration") put(ErrorsJs.WRONG_EXTERNAL_DECLARATION, "Declaration of such kind ({0}) can't be external", Renderers.STRING) put(ErrorsJs.EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION, "Function types with receiver are prohibited in external declarations") + put(ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION, "Using inline classes as parameter type or return type of external declarations is not supported") put(ErrorsJs.JS_NAME_CLASH, "JavaScript name ({0}) generated for this declaration clashes with another declaration: {1}", Renderers.STRING, Renderers.COMPACT) 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 e2c05c3ca66..031cd0e6e0a 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 @@ -1,17 +1,6 @@ /* - * 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. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.js.resolve.diagnostics; @@ -43,6 +32,7 @@ public interface ErrorsJs { DiagnosticFactory1 WRONG_EXTERNAL_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory0 EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory0 NESTED_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); + DiagnosticFactory0 INLINE_CLASS_IN_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory2 JS_NAME_CLASH = DiagnosticFactory2.create( ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt index f49b4826c87..4eafe9ac627 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt @@ -20,7 +20,9 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.descriptorUtil.* +import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils object JsExternalChecker : DeclarationChecker { @@ -84,6 +86,29 @@ object JsExternalChecker : DeclarationChecker { trace.report(ErrorsJs.INLINE_EXTERNAL_DECLARATION.on(declaration)) } + if (descriptor is CallableMemberDescriptor && !(descriptor is PropertyAccessorDescriptor && descriptor.isDefault)) { + fun checkTypeIsNotInlineClass(type: KotlinType, elementToReport: KtElement) { + if (type.isInlineClassType()) { + trace.report(ErrorsJs.INLINE_CLASS_IN_EXTERNAL_DECLARATION.on(elementToReport)) + } + } + + for (p in descriptor.valueParameters) { + val ktParam = p.source.getPsi() as? KtParameter ?: declaration + checkTypeIsNotInlineClass(p.varargElementType ?: p.type, ktParam) + } + + val elementToReport = when (declaration) { + is KtCallableDeclaration -> declaration.typeReference + is KtPropertyAccessor -> declaration.returnTypeReference + else -> declaration + } + + elementToReport?.let { + checkTypeIsNotInlineClass(descriptor.returnType!!, it) + } + } + if (descriptor is CallableMemberDescriptor && !(descriptor is PropertyAccessorDescriptor && descriptor.isDefault)) { for (p in descriptor.valueParameters) { if ((p.varargElementType ?: p.type).isExtensionFunctionType) {